With Java 9 method dropWhile()
was added to the Stream API. When I read the documentation, I found out that it is very similar to Java 8 filter()
method.
Am I missing something? What is the difference between these methods?
Let's have a look at this example:
Stream.of(1, 2, 3, 1)
.dropWhile(i -> i < 2)
.forEach(System.out::println);
System.out.println("====");
Stream.of(1, 2, 3, 1)
.filter(i -> i < 2)
.forEach(System.out::println);
which will give the following output:
2
3
1
====
1
1
Firstly, in ordered streams dropWhile
drops only the longest prefix of matching elements (see the docs). Also, you can see that filter
specifies which elements need to pass, while dropWhile
which to remove.
Here is a small program that shows the difference.
public class Example {
public static void main(String[] args) {
List<Integer> numbers = List.of(-1, -3, -4, 2, 5, -6, -7, 8);
// Prints: 2, 5, 8
System.out.println(numbers.stream()
.filter(n -> n >= 0)
.map(Object::toString).collect(Collectors.joining(", ")));
// Prints: 2, 5, -6, -7, 8
System.out.println(numbers.stream()
.dropWhile(n -> n < 0)
.map(Object::toString).collect(Collectors.joining(", ")));
}
}
filter
removes all the elements from the stream which do not match the predicate (in this case: n -> n >= 0
, so it removes the negative numbers).
dropWhile
removes the elements that do match the predicate (in this case: n -> n < 0
), until it finds an element that does not match the predicate. From that point on it lets all elements pass through.
Note that the predicates used for filter
and dropWhile
are each others' opposites in this example.
filter
- is a stateless intermediate operation which always returns a stream consisting only of elements the matches the given predicate.
Returns a stream consisting of the elements of this stream that match the given predicate.
dropWhile
- is a statefull intermediate operation, which also expects a predicate and basically acts like a stateful filter. After the first element which doesn't match the predicate has been encountered, dropWhile()
stops discarding elements from the stream.
If this stream is ordered then the longest prefix is a contiguous sequence of elements of this stream that match the given predicate.
If this stream is unordered , and some (but not all) elements of this stream match the given predicate, then the behavior of this operation is nondeterministic ; it is free to drop any subset of matching elements (which includes the empty set).
To understand the difference between in behavior of the dropWhile
with ordered and unordered stream, let's consider the following examples.
That would an example of unordered stream:
Set<Integer> numbers = Set.of(9, 1, 2, 3, 4, 5, 6, 7, 8);
numbers.stream()
.dropWhile(i -> i < 9)
.forEach(System.out::print);
Output can be for example 912
, it would range from 9
to 123456789
(meaning that all elements might be present, the order in the output would unpredictable). Because the stream is unordered elements from the source might appear in the stream, and dropWhile()
can be switched off at any point of execution, that's what the phrase "behavior is nondeterministic" in this case means.
Now let's take a look at the ordered stream :
List<Integer> numbers = List.of(9, 1, 2, 3, 4, 5, 6, 7, 8);
numbers.stream()
.dropWhile(i -> i < 9)
.forEach(System.out::print);
Output:
912345678
Since 9
, the very first element in the stream, doesn't match the predicate, it will never be evaluated again, dropWhile()
is being switched off and all element would reach the terminal operation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.