Java 9 has updated the Streams API and a few other features in addition to the Jigsaw modularity project (also known as The Big One). Let's go over some of the changes developers can expect when working with Streams.
Java 8 introduced Streams, which help developers perform aggregate operations from a sequence of objects. Meanwhile, Java 9 introduced a few more utility methods to make developers' work even easier.
1. takewhile(Predicate Interface) and dropwhile(Predicate Interface)
Both of these methods have an argument of the predicate functional interface type. takewhile will take all the values until the predicate returns false. Meanwhile, dropwhile will drop all the values until the predicate fails.
The filter utility method in Java 8 will retain all the elements when it matches the condition. But takewhile will stop once it has found an element it fails to match, like a Stream consisting of the longest prefix of elements taken from this Stream that matches the given predicate (ordered Stream). Dropwhile will throw away the elements at the start where the predicate is true. For example, it returns a Stream consisting of the remaining elements of this Stream after dropping the longest prefix of elements that match the given predicate (ordered Stream).
In an unordered case, both return the subset of elements as per their definition.
In the above example, takewhile will take all
abc values, then finds that the string is empty, so it stopped executing it. Then, dropwhile drops
abc, then takes all the values that match the condition.
Streams has the iterate method with two arguments: One is the initializer, which is called as a seed, and the other argument is the function to be applied to the previous element to produce the new element. But the drawback of that method is that there is no termination of that loop.
Stream.iterate(1, count->count+2 ).forEach(System.out::println);
The above statement will continue executing and never stops.
Java 9 updated the iterate method, which is similar to what we had earlier for loop-based iterations. This is the replacement of for loops. This also solves the problem that we had in the earlier iterate method.
iterate(initialize section; predicate section(hasNext); next section)
The iterate will stop once the hasNext section returns false.
In the above example, the value is initialized with 3 and increments each time by 3. The predicate condition is that the value should be less than 10. So, the output is 3, 6, 9.
Java 9 introduced the ofNullable method to return empty Optionals if the value is null. The main intention is to avoid NullPointerExceptions and to avoid having null checks everywhere.
Here, it returns the sequential Stream containing a single element if the value is not null — otherwise, it returns the empty Stream.
The below snippet will show the usage of nullable to avoid NullPointerExceptions.
Let's consider a practical scenario where we have to get
employee and then a list of roles the employee has been in.
Before Java 8
Employee emp= getEmployee(empId); Stream<Roles> roles= emp== null? Stream.empty(): emp.roles();
In the above cases, the
getEmployee method may return null, so we have done a null check and performed operations after that.
In Java 9
Employee emp= getEmployee(empId); Stream.ofNullable(emp).flatMap(Employee::roles)
This is an example scenario where we can use the ofNullable utility to reduce the number of lines in our code.
Note: Examples are solved the Jshell.