简体   繁体   中英

Java Stream - what is the difference between filter() and dropWhile()

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM