Java > Java 8 Features > Streams API > Stream Pipelines (filter, map, reduce)
Calculating the Sum of Even Numbers Using Stream Pipelines
This code snippet demonstrates the use of Java 8 Streams API to filter even numbers from a list, map them to their integer value, and then reduce the stream to calculate their sum. It illustrates a typical stream pipeline using filter
, mapToInt
, and sum
.
Code Snippet
The code initializes a list of integers. It then creates a stream from this list. The filter
operation selects only the even numbers (numbers divisible by 2). The mapToInt
operation converts the Integer
objects to primitive int
values, which is more efficient for numerical calculations. Finally, the sum
operation calculates the sum of the resulting stream of even numbers.
import java.util.Arrays;
import java.util.List;
public class StreamPipelineExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sumOfEvenNumbers = numbers.stream()
.filter(n -> n % 2 == 0) // Filter out odd numbers
.mapToInt(Integer::intValue) // Convert Integer to int
.sum(); // Calculate the sum
System.out.println("Sum of even numbers: " + sumOfEvenNumbers); // Output: 30
}
}
Concepts Behind the Snippet
This snippet showcases several key concepts of the Java 8 Streams API:
* Streams: A sequence of elements that supports sequential and parallel aggregate operations.
* Intermediate Operations: Operations like filter
and map
that transform the stream into another stream.
* Terminal Operations: Operations like sum
that produce a result or side-effect. Terminal operations mark the end of a stream pipeline.
* Functional Interfaces: filter
takes a Predicate
, and mapToInt
takes a ToIntFunction
, which are functional interfaces.
Real-Life Use Case
Imagine processing a large dataset of product sales records. You might use a stream pipeline to filter out sales below a certain threshold, map the sales amounts to their profit margins, and then reduce the stream to calculate the total profit for a specific period. This is a common pattern in data processing and analytics.
Best Practices
IntStream
, LongStream
, or DoubleStream
to avoid boxing/unboxing overhead.
Interview Tip
Be prepared to explain the difference between intermediate and terminal operations. Also, be able to discuss the performance implications of using streams, particularly regarding boxing/unboxing and parallel processing.
When to Use Them
Use stream pipelines when you need to perform a sequence of operations on a collection of data in a declarative and potentially parallelizable way. They are particularly useful for data processing, filtering, and aggregation tasks.
Memory Footprint
Streams are generally memory-efficient because they process data lazily. Intermediate operations are not executed until a terminal operation is invoked. This allows streams to process large datasets without loading the entire dataset into memory at once.
Alternatives
for
loops can be more efficient for very small datasets or when you need fine-grained control over the iteration process.
Pros
Cons
FAQ
-
What is the difference between
map
andmapToInt
?
map
transforms each element of the stream into another object.mapToInt
specifically transforms each element into anint
primitive, which can be more efficient for numerical calculations as it avoids boxing/unboxing. -
Can I use streams with any type of collection?
Yes, you can create a stream from anyCollection
(e.g.,List
,Set
) using thestream()
method. You can also create streams from arrays usingArrays.stream()
. -
What happens if I try to use a stream after a terminal operation has been called?
You will get anIllegalStateException
. Streams are designed to be used only once per pipeline.