Important changes in Java ☕ 8 ⇒ 11 (streams)

Featured image

What is intermediate operation and terminal operation?

Intermediate Operation (lazy) - these are methods of a stream and always return a Stream. As was said they are Lazy which means that they need a terminal operation to invoke them and that means that they do not process any data. They are only a declaration of the operation on a given stream. Same as String str is a variable declaration.

Terminal Operation (final) - these guys are not lazy, and they work very hard. Thanks to them computation on a stream is triggered and some side effect is performed such as count().

Intermediate operations - lazy Terminal/final operations
filter(Predicate) reduce
map(Function) forEach
peek(Consumer) toArray
flatmap(Function) min, max, count
sorted(Comparator) anyMatch, noneMatch, allMatch
limit(long n) findFirst
findAny collect
skip(long n) distinct()

Example intermediate and terminal operation:

.peek - mainly used for debugging purposes (returns a Stream just like all other intermediate operations).

.forEach -performs an action on each element of a stream (returns void). Triggers processing of data.

Data for given example:

var numbers = Stream.of("1", "12", "123", "1234");

This is good example of what cannot be infered by the compiler

// cannot infer type: lambda expression requires an explicit target type
var isTextLengthValid = text -> text.length() > 2;

// this works
Predicate<String> isTextLengthValid = text -> text.length() > 2;

Intermediate operation (lazy)

var result = new ArrayList<>();

numbers.filter(isTextLengthValid)  
        .peek(System.out::println) 
        .peek(result::add); // result list remains empty
result.size() // 0

Terminal operation (final)

var result = new ArrayList<>();

numbers.filter(isTextLengthValid) 
        .peek(System.out::println)        
        .forEach(result::add); // result list contains 2 elements            
result.size(); // 2

The stream can be called only once 👇

Can’t do

var tools = Arrays.asList("Hammer", "Nokia 3030");
var streamOfTools = tools.stream();

var firstCall = streamOfTools
                .peek(System.out::println)
                .collect(Collectors.joining(", "));

var secondCall = streamOfTools
        .peek(System.out::println)
        .collect(Collectors.joining(", ")); 

// Hammer,
// Nokia 3030,
// java.lang.IllegalStateException: stream has already been operated upon or closed

Can do

var tools = Arrays.asList("Hammer", "Nokia 3030");

var firstCall = tools
                .stream()
                .peek(System.out::println)
                .collect(Collectors.joining(", "));

var secondCall = tools
        .stream()
        .peek(System.out::println)
        .collect(Collectors.joining(", ")); 

// Hammer,
// Nokia 3030,
// Hammer,
// Nokia 3030,