Reputation: 3060
In a Java 8 stream with a filter condition, every element in the collection is passed to the filter for checking the condition. Here I am writing two different filter conditions and giving different workflows.
public static void main(String[] args) {
List<String> asList = Arrays.asList("a", "b", "c", "d", "e", "a", "b", "c");
//line 1
asList.stream().map(s -> s).filter(distinctByKey(String::toString)).forEach(System.out::println);
Predicate<String> strPredicate = (a) -> {
System.out.println("inside strPredicate method--");
return a.startsWith("a");
};
//line 2
asList.stream().filter(strPredicate).forEach(System.out::println);
}
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
System.out.println("inside distinctByKey method...");
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
In the above sample code, the statement line 1 filter condition is executing only once but line 2 is executing for every element in the collection output.
I thought the distinctByKey
method would execute for every element in the collection, but it is not the case. Why ?
Also the Set
object reference variable seen
is executing only once? How is the flow working?
Upvotes: 3
Views: 883
Reputation: 19910
distinctByKey
is a lambda factory method. It is returning a Predictate<T>
.
So when you execute: filter(distinctByKey(String::toString))
you're in fact calling the distinctByKey
method first, which then returns a Predicate
. That predicate then gets executed for every element. Just the factory function will only be executed once.
When moving the System.out.println
inside the returned lambda you'll get the desired print statements:
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
System.out.println("inside distinctByKey method...");
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> {
System.out.println("inside distinctByKey.lambda method... ");
return seen.add(keyExtractor.apply(t));
};
}
Upvotes: 18
Reputation: 121078
That seen
is captured by the lambda expression and cached inside the lambda, once you return the Predicate
- the Predicate::test
will be called multiple times with the same instance of seen
Upvotes: 4