Stream operations are combined to form stream pipelines.
A stream pipeline consists of the following.
Collection
, a generator function, or an I/O channel;Stream.filter
or Stream.map
;Stream.forEach
or Stream.reduce
.Intermediate operations
filter()
, map()
, sorted()
.Terminal operations
forEach()
, sum()
, max()
.Here is our previous pipeline.
public class StreamSolution2 {
public static void main(String[] args) {
Dog d1 = new Dog("Max", 50, 8);
Dog d2 = new Dog("Marley", 60, 10);
Dog d3 = new Dog("Rocky", 30, 5);
Dog d4 = new Dog("Bear", 70, 12);
Dog d5 = new Dog("Luna", 30, 13);
Dog d6 = new Dog("Luna", 25, 10);
List<Dog> dogs = List.of(d1, d2, d3, d4, d5, d6);
System.out.println("Original array: " + dogs);
List<String> nameList =
dogs.stream()
.filter(dog -> dog.height < 60 && dog.weight > 5)
.map(dog -> dog.name)
.distinct()
.sorted()
.collect(Collectors.toList());
System.out.println("Dog names: " + nameList);
}
}
Processing intermediate operations lazily is efficient. This way, we can
This behavior becomes even more important when the input stream is not finite.
Intermediate operations are further divided into stateless and stateful operations.
Stateless operations
filter()
, map()
.Stateful operations
distinct()
, sorted()
,Short-circuiting operations are just like boolean short-circuit evaluations.
An intermediate short-circuiting operation
limit()
.A terminal short-circuiting operation
findFirst()
, findAny()
.A reduction operation takes a sequence of input elements and combines them into a single summary result, for example,
finding the sum of a set of numbers,
[1, 2, 3, 4, 5] = 1 + 2 + 3 + 4 + 5 = 15
finding the average of a set of numbers,
[1, 2, 3, 4, 5] = (1 + 2 + 3 + 4 + 5)/5 = 3
finding the highest on a set of numbers,
[1, 2, 3, 4, 5] = 5
and accumulating elements into a list.
Here is an example of a reduction that sums elements in a list.
int sum = 0;
for (int x : numbers) {
sum += x;
}
And here is an equivalent code using streams:
int sum = numbers.stream().reduce(0, (x,y) -> x+y);
or:
int sum = numbers.stream().reduce(0, Integer::sum);
An advantage of using streams is that the solution is inherently parallelizable.
int sum = numbers.parallelStream().reduce(0, Integer::sum);
Mutable reduction: accumulates input elements into a mutable result container, such as:
Collection
StringBuilder
Immutable reduction accumulates input elements into an immutable variable, such as:
int
boolean
The streams classes have general reduction operations, which repeatedly apply a combining operation:
reduce()
: to perform an immutable reductioncollect()
: to perform a mutable reductionCommon reduction operations are:
sum()
max()
count()