Stream API in Java | Generated by AI
To use java.util.stream in Java, you can leverage the Stream API introduced in Java 8 to process collections of data in a functional and declarative way. Streams allow you to perform operations such as filtering, mapping, and reducing on sequences of elements (like lists or arrays) efficiently and concisely. Below, I’ll explain how to use java.util.stream by walking through a specific example: finding the average of even numbers greater than 10 from a list of integers. This will demonstrate key stream operations and concepts.
Overview of java.util.stream
The java.util.stream package provides the Stream interface and related classes (like IntStream, DoubleStream, etc.) to process data. A stream is a sequence of elements that supports operations executed in a pipeline. These operations are:
- Intermediate operations: Transform or filter the stream (e.g.,
filter,map), returning a new stream. These are lazy and only executed when a terminal operation is invoked. - Terminal operations: Produce a result or side effect (e.g.,
average,collect), triggering the pipeline to process the data.
To use streams, you typically:
- Create a stream from a data source (e.g., a list).
- Apply intermediate operations to transform or filter the data.
- Use a terminal operation to produce a result.
Example Problem
Let’s solve this problem: Given a List<Integer>, compute the average of all even numbers greater than 10. If no such numbers exist, return 0.0. Here’s how to do it using java.util.stream.
Step-by-Step Solution
- Create a Stream
- Start with a
List<Integer>(e.g.,List.of(1, 2, 12, 15, 20, 25, 30)). - Use the
stream()method to create aStream<Integer>:list.stream()
- Start with a
- Filter the Stream
- Use the
filtermethod to keep only numbers that are even and greater than 10. - The
filtermethod takes aPredicate(a function returning a boolean) as a lambda expression:.filter(number -> number % 2 == 0 && number > 10)number % 2 == 0checks if a number is even.number > 10ensures the number is greater than 10.- For the example list
[1, 2, 12, 15, 20, 25, 30], this keeps[12, 20, 30].
- Use the
- Convert to an
IntStream- Since
average()is available on primitive streams likeIntStream(notStream<Integer>), convert theStream<Integer>to anIntStreamusingmapToInt:.mapToInt(i -> i)i -> iunboxes eachIntegerto anint. Alternatively, you could useInteger::intValue.- This gives an
IntStreamof[12, 20, 30].
- Since
- Compute the Average
- Use the
average()method onIntStream, which returns anOptionalDouble(since the stream might be empty):.average()- For
[12, 20, 30], this computes(12 + 20 + 30) / 3 = 20.666.... - If the stream is empty, it returns an empty
OptionalDouble.
- For
- Use the
- Handle the Empty Case
- Use
orElse(0.0)on theOptionalDoubleto return 0.0 if no numbers satisfy the filter:.orElse(0.0)- For
[12, 20, 30], this returns20.666.... - For a list like
[1, 3, 5](no even numbers > 10), it returns0.0.
- For
- Use
Complete Code
Here’s the full solution as a method:
import java.util.List;
public class Main {
public static double averageOfEvenGreaterThanTen(List<Integer> list) {
return list.stream()
.filter(number -> number % 2 == 0 && number > 10)
.mapToInt(i -> i)
.average()
.orElse(0.0);
}
public static void main(String[] args) {
// Test cases
System.out.println(averageOfEvenGreaterThanTen(List.of(1, 2, 12, 15, 20, 25, 30))); // ~20.666
System.out.println(averageOfEvenGreaterThanTen(List.of(1, 3, 5))); // 0.0
System.out.println(averageOfEvenGreaterThanTen(List.of(12))); // 12.0
System.out.println(averageOfEvenGreaterThanTen(List.of())); // 0.0
System.out.println(averageOfEvenGreaterThanTen(List.of(10, 8, 6))); // 0.0
System.out.println(averageOfEvenGreaterThanTen(List.of(11, 13, 14, 16))); // 15.0
}
}
Key Features of java.util.stream Demonstrated
- Chaining: Operations are chained in a fluent style (e.g.,
.filter().mapToInt().average()). - Laziness: Intermediate operations (like
filterandmapToInt) are only executed when the terminal operation (average) is called. - Primitive Streams:
IntStreamprovides methods likeaverage()tailored for numeric operations, avoiding boxing overhead. - Optional Handling:
OptionalDoublehandles cases where no result exists, withorElseproviding a default value.
Alternative Approach
You could also use the Collectors class:
import java.util.stream.Collectors;
double average = list.stream()
.filter(number -> number % 2 == 0 && number > 10)
.collect(Collectors.averagingInt(i -> i));
- This returns a
Doubledirectly and returns0.0for an empty stream. However,mapToInt().average()is more direct for this simple case and aligns with primitive stream usage.
When to Use Streams
- Use
java.util.streamfor concise, readable code when processing collections. - For large datasets, consider
parallelStream()instead ofstream()to leverage parallelism, though this is overkill for small lists due to overhead.
This example shows how to use java.util.stream to solve a practical problem. You can adapt these steps—creating a stream, filtering, mapping, and reducing—to other scenarios as needed!