Arguably one of the most noteworthy new features introduced in Java 8 was the Streams API. It allowed developers to declaratively manipulate collections using functional style programming. Since the release of Java 9 is just around the corner, let’s have a look at two new stream operations in Java 9—
takeWhile is similar to
filter in the sense that it expects a predicate and returns a new stream consisting only of the elements that match the given predicate. But there’s a catch. In an ordered stream,
takeWhile takes elements from the initial stream while the predicate holds
true. Meaning that when an element is encountered that does not match the predicate, the rest of the stream is discarded. Let’s have a look at the following example.
In this example, we’re taking even numbers from the initial stream until the first odd number is encountered. The stream returned by
8. It does not contain
9 since it did not match the predicate. Although
12 are even, they’re not included in the returned stream as well because the stream operation was cut off when
9 was encountered.
dropWhile is essentially the opposite of
takeWhile. Instead of taking elements from the stream until the first element which does not match the predicate,
dropWhile drops these elements and includes the remaining elements in the returned stream.
The following is the same example we used previously with one noteworthy difference.
takeWhile has been replaced with
In an ordered stream,
dropWhile removes the longest contiguous sequence of elements that match the given predicate. In this example we’re dropping even numbers.
8 are removed because applying the predicate on them returns
9 isn’t an even number and is therefore included in the result. Even though
12 are even numbers, they’re included in the result because they came after the first element which failed the predicate.
So far we’ve looked at how
dropWhile behave with ordered streams. But what happens if the stream is unordered? According to the docs, if some of the elements in the stream match the predicate (but not all) then the operation is nondeterministic and an arbitrary subset of matching elements is returned or removed. Meaning that you’ll get different results for each execution.
You can expect a similar behavior if you replace
dropWhile. It’s free to drop any subset of matching elements. That includes the empty set.
All elements match
Regardless of whether the stream is ordered or unordered, if all elements match the given predicate then
takeWhile takes and
dropWhile drops all elements. The result of
takeWhile is the same as the input stream. On the other hand, when all elements match, the result of
dropWhile will be an empty stream.
The following is an example of
takeWhile applied on an unordered stream where all the elements match the predicate.
No elements match
I bet you can already guess what happens if no elements match the given predicate. You’re right if you guessed that the result of
takeWhile will be an empty stream. Since no elements matched, there’s nothing to take.
dropWhile, on the other hand, returns the input stream if there’s nothing to drop.
dropWhile are expensive operations on ordered parallel streams. Threads have to cooperate to find the longest contiguous sequence of matching elements in encounter order and this can significantly impact performance. Using a sequential stream may give you better results.
dropWhile are new additions to the Streams API introduced in Java 9. In ordered streams, they take or drop the longest contiguous sequence of elements from the stream based on the given predicate. However, in unordered streams, their behavior is nondeterministic. They’re free to take or drop any arbitrary subset of elements.