Java 9 enhancements to Optional/Stream

Java 9 will be released soon and its NOT all about Jigsaw. It brings also some extra utilities and changes under the hood. In this post, we'll work through Java 9 additions to Optional and Stream API.

Optional

Optional::ifPresentOrElse

This new method checks if a value is present, performs the given action with the value, otherwise performs the given empty-based action.

void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction);

in other words, it encodes a common pattern where you want to perform an action if an Optional value is present, or a different action if it’s absent.

In order to understand it better, let's take an example of a method that check if a student exist or not using the student Id Nb, and see how you would write this code both using null checks and also the Optional type.

Using null Checks:
Student student = getStudentByIdNo(studentIdNo);
         if (student != null) {
displayStudentInfo(student);
} else {
displayStudentNotFound();
}
Using Java 8 Optional:

Much cleaner and better, isn't ?!

 getStudentByIdNo(studentIdNo).
             ifPresent( this::displayStudentInfo)
Using the new Java 9 Optional::ifPresentOrElse:
 getStudentByIdNo(studentIdNo).ifPresentOrElse( this::displayStudentInfo, ()-> displayStudentNotFound());

Optional::or

Another method that has been added to Optional in Java 9 is the succinctly named or() method. This method takes a function that creates an Optional as an argument. If the value is present returns an Optional describing the value, otherwise returns an Optional produced by the supplying function.

public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)

This is particularly useful when you have a couple of methods that all return optionals and you want to return the first one that is present. Let’s suppose that we want to lookup information about Student’s using again his Id number. Firstly we want to check our existing student in the current college year. If it isn’t we check in the archive.

public Optional<Student> getStudentByIdNo(String studentIdNo) {
return findInCurrentCollegeYear(studentIdNo)
       .or(() -> findInArchive(studentIdNo));
}

Optional::stream

This is a long waited method. it returns a sequential Stream, if a value is present, that contain only present value, otherwise returns an empty Stream.
public Stream<T> stream()

For example, let’s suppose you want to get all students using a collection of Students Id No. You’ve implemented a getStudentByIdNo method that returns an Optional if a student has been found.

Using java 8
public List<Student> getStudentList(Collection<String> studentIdNo) {
return studentIdNo.stream()
    .map(this::getStudentByIdNo)
    // now we have a Stream<Optional<Student>>
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(toList());
}

In this example we’re combining two optional methods to achieve our goal. We’ve used a filter on the isPresent() method in order to remove empty Optionals. We then unboxed the optionals that we knew had a value in with the get() method call.

Using java 9
public List<Student> getStudentList(Collection<String> studentIdNo) {
return studentIdNo.stream()
    .map(this::getStudentByIdNo)
    .flatMap(Optional::stream)
    .collect(toList());
}

It looks more cleaner than what we had to do before.

Optional::get

There is a proposal to deprecate Optional.get() and rename it to something else. Despite this proposal having merit the schedule constraints mean that it is unlikely to make Java 9, but might happen in Java 10.

Stream

Stream::takeWhile

This method returns longest prefix elements which matches the Predicate condition.
default Stream<T> takeWhile(Predicate<? super T> predicate)

It takes a Predicate as an argument. A Predicate is Boolean expression which returns either true or false. It behaves differently for ordered and unordered Streams.

Ordered Stream

If the stream is ordered then the longest prefix is a contiguous sequence of elements of this stream that match the given predicate. The first element of the sequence is the first element of this stream, and the element immediately following the last element of the sequence does not match the given predicate.

       Stream.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
.takeWhile(i -> i < 10)
.forEach(System.out::println)

## Output: 1 2 3 4 5 6 7 8 9
Unordered Stream

If the stream is unordered, and some (but not all) elements of this stream match the given predicate, then the behavior of tackeWhile operation is nondeterministic; it is free to take any subset of matching elements (which includes the empty set).

Stream.of(2,6,4,1,7,9,8,4,3,5)
.takeWhile(i -> i < 4)
.forEach(System.out::print)

## Output: 2

takeWhile returns all prefixed elements until they match Predicate condition (less than 10/ in the 1st/2nd example). When that Predicate returns false for first element, then it stops evaluation and returns that subset elements.

Stream::dropWhile

dropWhile does simply the opposite of takeWhile, i.e it returns, if this stream is ordered, a stream consisting of the remaining elements of this stream after dropping the longest prefix of elements that match the given predicate. Otherwise returns, if this stream is unordered, a stream consisting of the remaining elements of this stream after dropping a subset of elements that match the given predicate.

default Stream<T> dropWhile(Predicate<? super T> predicate)

## Ordered Stream
Stream.of(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
.dropWhile(i -> i < 10)
.forEach(System.out::println)
## Output: 10 11 12 13 14 15 16 17 18 19 20

## Unordered Stream
Stream.of(2,6,4,1,7,9,8,4,3,5)
.dropWhile(x -> x < 4)
.forEach(System.out::println)

## Output: 6 4 1 7 9 8 4 3 5

Stream::ofNullable

ofNullable returns a sequential Stream containing a single element, if non-null, otherwise returns an empty Stream. Genius, isn't ?!

static <T> Stream<T> ofNullable(T t)

It has its use cases, though. Before, if some evil API gave you an instance that could be null, it was circuitous to start operating on a stream that instance could provide:

// getStudentByIdNo can return null
Student student = getStudentByIdNo(studentIdNo);

Optional.ofNullable(student)
.map(student::streamGrades)
.orElse(Stream.empty()
.// do something with stream of Grades

This gets much better now:

// getStudentByIdNo can return null
Student student = getStudentByIdNo(studentIdNo);

Stream.ofNullable(student)
.flatMap(student::streamGrades)
.// do something with stream of Grades

Stream::iterate

A related update is the introduction of an alternative iterate() method for creating streams. The vintage iterate method from Java 8 takes an initial value and a function that provides the next value in the Stream. Take a look at the following code example:

IntStream.iterate(1, i -> i + 1).forEach(System.out::println);

The question quickly comes to mind after running the example is how to make it stop ?! The answer is ... you can't, it's an infinite stream. We can solve this with the new version of iterate in Java 9 which also takes a predicate as its second argument that tells us when to continue iterating up until.

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)

So we rewrite our code as follows:

IntStream.iterate(1, i -> i<15, i -> i + 1).forEach(System.out::println);

Voila! it now stops running after it has printed out the number 14.

That's all ;) Please drop me a comment if you've any issues/suggestions/type errors.