Stream API in Java
In Java 8, every class which implements the java.util.Collection
interface has a stream
method which allows you to convert its instances intoStream
objects.
- Technically: typed interface
- Extends: BaseStream
- Also has: IntStream, LongStream, DoubleStream based on primitive data types int, long and double
Properties:
Does not hold data
- pulls data from given source
- connects to source, consumes the data and processes it
Does not modify data
- because data is processed in parallel with no visibility issues
- not enforced by compiler, merely a contract
Source may be unbounded
- not finite meaning number of elements produced by the source is unknown at build time
Patterns for building
Stream.empty(); // an empty stream
Stream.of("one"); // singleton stream
Stream.of("one", "two", "three"); // stream with multiple elements
Stream.generate(() -> "one"); // constant stream using Supplier
Made usingStream.iterate("+", s -> s + "+"); // a growing stream
UnaryOperator
which takes an element and returns another of the same type.iterate
takes the current element of the stream as the first argument, gets the result from theUnaryOperator
of the second argument and uses that as the next element in the stream.ThreadLocalRandom.current().ints(); // a random stream
IntStream stream = "hello".chars();
chars
method returns an int stream based on the letters of the characters.IntStream stream = "hello".chars();
chars
method returns an int stream based on the letters of the characters. -
The Pattern class implements the regular expression engine in JDK. It provides a Pattern object by calling theStream<String> words = Pattern.compile().splitAsStream(something); // stream on a regular expression
compile
static method. -Stream<String> lines = Files.lines(path); // stream on the lines of a text file
Terminal v/s Intermediate operation
A terminal operation must be called to trigger processing on the stream. Without it, no data is consumed, processed or returned.
Example
forEach
v/s peek
. We cannot substitute forEach
calls with peek
calls as peek
is an intermediate operation created for debugging purposes.
Differentiating
- Javadoc specifies terminal or intermediate
- A call that returns Stream -> intermediate. A call that returns something else or void -> terminal
Functions
- map
- filter
- peek
- forEach
- skip
- limit
- Match Reductions returning boolean -> anyMatch (any element), allMatch (all elements), noneMatch ^^^ may not evaluate predicate for all elements -> short circuiting terminal operations
- Find Reductions -> findFirst (returns any if the stream is unordered -> built on a set etc), findAny
Reduce Reductions
1. Provided the list has only positive numbers (since the identity for max is 0 over a positive range)
int maxNum =
list.stream()
.reduce(0, (p1, p2) -> Integer.max(p1, p2));
2. If identity element is not provided, Optional is returned -> result of the reduction on an empty stream is not defined
Optional<Integer> maxNum =
list.stream()
.reduce((p1, p2) -> Integer.max(p1, p2));