Java Stream API was one of the major features released with Java 8, that let you code in declarative style.
It supports function-style operations on streams of elements, such as map, filter and various other transformations.
Streams vs Collection
It is a myth that Java Stream API have replaced Collections in Java. Most of the collections are a main source for the stream to work on and they are often used together.
Some of the major difference between Streams and Collection are:
Collection | Stream | |
Storage | Storage of data. Collections are about data. | No storage of data. Streams are about computations on data |
Data Modification | Can add/remove elements | Functional in nature. Operations on stream eg. filtering will result in a new Stream |
Iteration | External iteration on Collections using loops | Perform iteration internally |
Traversal | Can be traversed multiple times | Traversable only once |
Evaluation | Eager evaluation; All elements are computed in the beginning itself | Lazy evaluation; Intermediate operations are not evaluated until terminal operation is invoked. |
Creating a Stream
String[] arr = {"d", "b", "c"};
System.out.println("Sorted Stream: " + Stream.of(arr).sorted().collect(Collectors.toList()));
The above code snippet creates a Stream from using Stream.of() and sorts the stream in its natural order, returning a sorted list as output.
Stream Operations

Intermediate operations
Intermediate operations are the ones that return the stream itself. Some of them are:
filter()
It accepts a predicate to filter all elements of the stream. This operation acts as an intermediate by enabling us to call another stream operation on the result.
For example,
knolders.stream().filter((str) -> str.startsWith("K"))
.forEach(System.out::println);
map()
map lets you convert the given element into another object.
knolders.stream().filter((str) -> str.startsWith("K"))
.map(String::toUpperCase)
.forEach(System.out::println);
Terminal Operations
Terminal operations return a result of a certain type instead of returning a Stream.
forEach()
It helps in iterating over all elements of a stream and perform some operation on the elements.
memberNames.forEach(System.out::println);
collect()
Collect is a useful terminal operation used to transform the elements of the stream into a different kind of result, e.g. a List, Set or Map.
It accepts a Collector which consists of four different operations: a supplier, an accumulator, a combiner and a finisher.
Java 8 onwards supports various built-in collectors via the Collectors class.
List<String> namesInUppercase = knolders.stream().sorted()
.map(String::toUpperCase)
.collect(Collectors.toList());
reduce()
The reduction operation combines all elements of the stream into a single result.
Optional<String> reduced = knolders.stream()
.reduce((s1,s2) -> s1 + "@" + s2);
reduced.ifPresent(System.out::println);
Short circuiting operations
Short-circuiting operations allow the computations on infinite streams to complete in finite time. Some of the short-citcuiting operations are:
limit()
It limits the stream elements to process.
int [] arr = {1,2,3,4,5,6,7,8,9,11};
Arrays.stream(arr)
.limit(5)
.forEach(System.out::println);
findFirst(), findAny()
firstFist() returns the first element from the Stream.
findAny() returns any element from the Stream. It may be possible to get a different result every time with findAny() operation.
int [] arr = {1,2,3,4,5,6,7,8,9};
Integer findFirstElem = Arrays.stream(arr).filter(i -> (i%2) == 0)
.findFirst()
.orElse(-1);
Integer findAnyElem = Arrays.stream(arr).filter(i -> (i%2) == 0)
.findAny()
.orElse(-1);
allMatch(), anyMatch()
These short circuit operators returns true or false value depending on the condition being evaluated.
allMatch() evaluates the condition for all the steams and will return a boolean value.
anyMatch() evaluates the condition in the stream until it finds its match and once the match is found, It exits the processing and returns a boolean value.
int [] arr = {1,2,3,4,5,6,7,8,9,11};
System.out.println("All numbers are greater than -1 : " + Arrays.stream(arr).allMatch(i-> i > -1));
System.out.println("Contains any numbers greater than 10 : " + Arrays.stream(arr).anyMatch(i-> i > 10));
References
- https://www.baeldung.com/java-streams
- https://blog.knoldus.com/merge-lists-of-map-to-map-java-8-style/
- Java 8 Documentation