Welcome back! Now that you have a basic understanding of Java Streams and how to create and use them, it’s time to dive into some more powerful stream operations. In this lesson, we will focus on intermediate operations such as filtering, mapping, and transforming streams. These operations will enable you to manipulate data more effectively and make your code cleaner and more efficient.
- How to filter elements in a stream based on a condition.
- How to transform elements in a stream using mapping.
- How to flatten a list of lists using
flatMap
.
By the end of this lesson, you’ll be proficient in using these intermediate operations, allowing you to perform complex data transformations with ease.
Intermediate operations allow you to process and transform data within streams. Unlike terminal operations, intermediate operations are lazy and do not execute until a terminal operation is invoked. Let's break down a few key intermediate operations with examples.
To filter elements in a stream, you can use the filter
method. This allows you to include only the elements that match a given condition.
Java1List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 2 3numbers.stream() 4 .filter(n -> n % 2 == 0) 5 .forEach(n -> System.out.println("Even number: " + n));
We start with a list of integers. The filter
method takes a predicate (a function that returns a boolean) and includes only the elements that match the condition (n % 2 == 0
means the number is even). The result is printed directly using the forEach
method.
Output:
1Even number: 2 2Even number: 4
The map
method is used to transform elements within a stream. You provide a function that defines the transformation.
Java1numbers.stream() 2 .map(n -> n * n) 3 .forEach(s -> System.out.println("Square: " + s));
Here, we use the same list of integers. The map
method takes a function (n -> n * n
) that squares each element. The result is printed directly using the forEach
method.
Output:
1Square: 1 2Square: 4 3Square: 9 4Square: 16 5Square: 25
When working with nested structures, you can use the flatMap
method to flatten them into a single stream.
Java1List<List<Integer>> listOfLists = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5)); 2 3listOfLists.stream() 4 .flatMap(List::stream) 5 .forEach(i -> System.out.println("Flattened number: " + i));
We start with a list of lists. The flatMap
method is used here to convert each inner list into a stream using List::stream
, which then flattens the nested structure into a single stream of integers. Note that we first call .stream()
on the outer list to process its elements. The result is then printed directly using the forEach
method.
Output:
1Flattened number: 1 2Flattened number: 2 3Flattened number: 3 4Flattened number: 4 5Flattened number: 5
Understanding and effectively using these intermediate stream operations is crucial for several reasons:
- Data Manipulation: These operations allow you to filter, transform, and restructure data effortlessly, making your code more powerful and expressive.
- Efficiency: Streams process elements in a lazy, efficient manner. By chaining operations, you can build complex data pipelines that are executed in a single pass.
- Readability: Using stream operations can make your code more readable and concise, reducing the need for nested loops and temporary variables.
Imagine a scenario where you need to filter a list of customer orders to find those placed in the last month, then transform the data to calculate total spend per customer, and finally flatten the results for further processing. With streams, you can achieve this in just a few lines of code!
By mastering these intermediate operations, you become more adept at writing elegant and efficient Java code, preparing you for more advanced stream processing tasks.
Now that you have a comprehensive understanding of filtering, mapping, and transforming streams, it’s time to get hands-on. Proceed to the practice section where you'll apply these operations to solve real-world problems. Let's get started!