Java 9 Stream API Improvements

1. Overview

In this quick write-up, we are going to focus on the new interesting Stream API improvements coming in Java 9.

2. Stream Takewhile/Dropwhile

Discussions about these methods have appeared repeatedly on StackOverflow (the most popular is this one).

Imagine that we want to generate a Stream of Strings by adding one character to the previous Stream‘s value until the length of the current value in this Stream is lower than 10.

How would we solve it in Java 8? We could use one of the short-circuiting intermediate operations like limitallMatch that actually serve for other purposes or write our own takeWhile implementation based on a Spliterator that, in turn, complicates such a simple issue.

With Java 9, the solution is easy:

Stream<String> stream = Stream.iterate("", s -> s + "s")
  .takeWhile(s -> s.length() < 10);

The takeWhile operation takes a Predicate which is applied to elements to determine the longest prefix of these elements (if a stream is ordered) or a subset of the stream’s elements (when a stream is unordered).

To move forward, we had better understand what terms “the longest prefix” and “a Stream’s subset” mean:

  • the longest prefix is a contiguous sequence of elements of the 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’s subset is a set of some (but not all) elements of the Stream match the given predicate.

After introducing these key terms, we can easily comprehend another new dropWhile operation.

It does exactly the opposite of takeWhile. If a stream is ordered, the dropWile returns a stream consisting of the remaining elements of this Stream after dropping the longest prefix of elements that match the given predicate.

Otherwise, if a Stream is unordered, the dropWile returns a stream consisting of the remaining elements of this Stream after dropping a subset of elements that match the given predicate.

Let’s throw away the first five elements by using the preceding obtained Stream:

stream.dropWhile(s -> !s.contains("sssss"));

Simply put, the dropWhile operation will remove elements while the given predicate for an element returns true and stops removing on the first predicate’s false.

3. Stream Iterate

The next new feature is the overloaded iterate method for finite Streams generation. Not to be confused with the finite variant which returns an infinite sequential ordered Stream produced by some function.

A new iterate slightly modifies this method by adding a predicate which applies to elements to determine when the Stream must terminate. Its usage is very convenient and concise:

Stream.iterate(0, i -> i < 10, i -> i + 1)
  .forEach(System.out::println);

It can be associated with the corresponding for statement:

for (int i = 0; i < 10; ++i) {
    System.out.println(i);
}

4. Stream Ofnullable

There are some situations when we need to put an element into a Stream. Sometimes, this element may be a null, but we don’t want that our Stream contains such values. It causes of writing either an if statement or a ternary operator which checks whether an element is a null.

Assuming that collection and map variables, have been created and filled successfully, have a look at the following example:

collection.stream()
  .flatMap(s -> {
      Integer temp = map.get(s);
      return temp != null ? Stream.of(temp) : Stream.empty();
  })
  .collect(Collectors.toList());

To avoid such boilerplate code, the ofNullable method has been added to the Stream class. With this method the preceding sample can be simply transformed into:

collection.stream()
  .flatMap(s -> Stream.ofNullable(map.get(s)))
  .collect(Collectors.toList());

5. Conclusion

We considered major changes of Stream API in Java 9 and how these improvements will help us to write more emphatic programs with fewer efforts.

As always, the code snippets can be found over on Github.

Related posts:

Java Program to Implement Skew Heap
Working with Tree Model Nodes in Jackson
Java Program to do a Depth First Search/Traversal on a graph non-recursively
How to Read a File in Java
Java Program to Find Transpose of a Graph Matrix
Java equals() and hashCode() Contracts
HttpClient 4 – Follow Redirects for POST
Spring 5 Functional Bean Registration
Java Program to Implement Attribute API
Creating Docker Images with Spring Boot
Java Program to Implement Hash Tables
Java Program to Generate a Sequence of N Characters for a Given Specific Case
Giới thiệu Google Guice – Dependency injection (DI) framework
Prevent Cross-Site Scripting (XSS) in a Spring Application
Java Program to Represent Graph Using Adjacency Matrix
Java Program to Create a Balanced Binary Tree of the Incoming Data
A Custom Data Binder in Spring MVC
Spring Security Authentication Provider
Java Program to implement Circular Buffer
Tìm hiểu về xác thực và phân quyền trong ứng dụng
A Guide to ConcurrentMap
Java Program to Implement Wagner and Fisher Algorithm for online String Matching
Giới thiệu Java Service Provider Interface (SPI) – Tạo các ứng dụng Java dễ mở rộng
Java Program to Generate All Possible Combinations of a Given List of Numbers
Extra Login Fields with Spring Security
A Guide to Spring Boot Admin
Guide to @JsonFormat in Jackson
Java InputStream to Byte Array and ByteBuffer
Lớp Collectors trong Java 8
Convert char to String in Java
Composition, Aggregation, and Association in Java
Hướng dẫn Java Design Pattern – Observer