Intermediate Operations
Intermediate operations build the stream pipeline by specifying what transformation or filtering logic should be applied. They always return a new Stream, allowing multiple intermediate operations to be chained together continuously.
1. Filtering: filter, distinct
Used when extracting elements that match a specific condition or removing duplicates.
filter(Predicate): Selects elements that satisfy the given condition (a lambda expression returning true).distinct(): Removes duplicate elements from the stream (usingObject.equals()internally).
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
numbers.stream()
.distinct() // Removes duplicates: 1, 2, 3, 4, 5
.filter(n -> n % 2 == 0) // Extracts even numbers: 2, 4
.forEach(System.out::println);
2. Transformation: map, flatMap
Extremely common operations used to transform the shape or type of data.
map(Function): Replaces each element in the stream with a different value, or extracts specific fields from an object.flatMap(Function): Flattens nested structures (e.g., a list of string arrays) into a single, unified stream.
List<String> words = Arrays.asList("apple", "banana", "cherry");
// Convert all words to uppercase
words.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // APPLE, BANANA, CHERRY
// flatMap example
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")
);
// Flatten into a single layer structure
nestedList.stream()
.flatMap(Collection::stream)
.forEach(System.out::print); // Prints ABCD
3. Sorting: sorted
Sorts the elements. If no arguments are passed, it uses the natural ordering (Comparable). Alternatively, a custom Comparator can be provided.
List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
// Alphabetical Sort
names.stream()
.sorted()
.forEach(System.out::println); // Alice, Bob, Charlie
// Reverse Alphabetical Sort
names.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println); // Charlie, Bob, Alice
4. Truncating: limit, skip
limit(long maxSize): Truncates the stream to contain no more than the specified number of elements.skip(long n): Discards the firstnelements of the stream.
IntStream.rangeClosed(1, 10) // 1 through 10
.skip(3) // Skips 1, 2, 3 (Starts from 4)
.limit(2) // Only takes 2 elements
.forEach(System.out::println); // Prints 4, 5
By assembling these versatile intermediate operations like Lego blocks, developers can construct powerful and readable data processing pipelines.