I am using Java in my project. I see code like below and not able to understand the flow.
public static void main(String[] args) {
Person p1 = new Person("test1");
Person p2 = new Person("test2");
List<Person> l = List.of(p1, p2);
var count = l.stream().filter(checkMethod(Person::getName)).count();
System.out.println(count);
}
public static final <T> Predicate<T> checkMethod(Function<? super T, ?> keyExtractor) {
Objects.requireNonNull(keyExtractor);
final var seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
Person.java
public class Person {
Person(String name) {
this.name = name;
}
private String name;
//getters and setters for name
}
}
It identifies the count of unique name from list of person objects. I see check method is called only once. But usually filter method will be executed for each items in list.
Is it like entire list of persons is sent to check method and called only once?
CodePudding user response:
Let's take a look what .filter(checkMethod(Person::getName))
actually does and how it works:
- At first
checkMethod(Person::getName)
is executed and returns a Predicate, which is the argument required for thefilter(..)
method - then,
filter(t -> seen.add(t.getName()))
is executed for every item on the stream - As
Collection.add(..)
returns a boolean indicating whether the element as added, every item is removed whose name was already seen
CodePudding user response:
checkMethod()
generates a stateful predicate.
While executing checkMethod()
JVM evaluates the lambda expression (lambdas are always evaluated at Runtime) and creates an instance of a Functional interface (Predicate
) which captures the reference to the Set
seen
. I.e. local variable seen
in the method would vanish when the method terminates, but the Predicate
would hold the reference to this object to it, so the Set
alive until the predicate is alive.
But usually
filter
method will be executed for each items in list.
And it would be called only once. Each stream element would be checked against the instance of Predicate
returned by checkMethod()
using Predicate.test()
.
In other words, method test()
would be invoked on the predicate for every element in the stream, but invocation of checkMethod()
would occur only one and each element would be checked against the same predicate.
So, you're confusing the creation of a Predicate
via checkMethod()
, and validation of elements via Predicate.test()
.