我在我的项目中使用Java。我看到下面的代码,但不能理解流程。
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
}
}
它标识了来自person对象列表的唯一名称的计数。我看到check方法只被调用一次。但是通常filter方法将对列表中的每个项目执行。
是不是整个人员列表都被发送到check方法,并且只调用一次?
2条答案
按热度按时间ljo96ir51#
让我们来看看
.filter(checkMethod(Person::getName))
实际上是做什么的,以及它是如何工作的:checkMethod(Person::getName)
并返回一个Predicate,这是filter(..)
方法所需的参数filter(t -> seen.add(t.getName()))
Collection.add(..)
返回一个布尔值,指示是否添加了元素,因此删除了名称已被看到的每个项monwx1rj2#
checkMethod()
生成一个 * 有状态 * predicate 。在执行
checkMethod()
时,JVM计算lambda表达式(* lambda始终在运行时求值 *)并创建 * 函数接口 * 的示例(Predicate
),其捕获对Set
seen
的引用。即,当该方法终止时,该方法中的局部变量seen
将消失,但是Predicate
将保持对该对象的引用,因此Set
在 predicate 活动之前是活动的。但通常
filter
方法将对列表中的每个项执行。每个流元素都将根据
checkMethod()
使用Predicate.test()
返回的Predicate
示例进行检查。换句话说,方法
test()
将在流中的每个元素的 predicate 上被调用,但是checkMethod()
的调用将仅发生一次,并且每个元素将针对相同的 predicate 被检查。因此,您混淆了通过
checkMethod()
创建Predicate
和通过Predicate.test()
验证元素。