Java Stream的distinctByKey执行原理及是否无状态解析
问题解答
1. 为什么Set<Object> seen = ConcurrentHashMap.newKeySet();仅执行一次,而seen.add(keyExtractor.apply(t));对每个元素执行?
当你调用distinctByKey(userInfo -> userInfo.id)时,distinctByKey方法会完整执行一次:此时seen的初始化语句会被执行,创建一个新的ConcurrentHashMap KeySet实例,随后方法返回一个捕获了该seen集合的Lambda表达式(即Predicate对象)。
而Stream的filter操作会遍历列表中的每一个元素,对每个元素都会调用这个Predicate的test方法(也就是Lambda中的逻辑),因此seen.add(keyExtractor.apply(t))会随着每个元素的处理被执行一次。总结来说:distinctByKey方法仅被调用一次,所以seen的初始化只做一次;而返回的Predicate会被每个元素触发调用,所以add操作会执行多次。
2. distinctByKey方法是否为无状态方法?
要区分方法本身和它返回的对象:
distinctByKey方法本身:它是静态方法,没有持有任何类级别的静态变量,每次调用都会创建一个全新的seen集合,方法执行完毕后不会保留任何状态,因此方法本身是无状态的。- 返回的Predicate对象:这个Predicate持有了
seen集合,每次调用test方法都会修改该集合的状态,所以这个Predicate是有状态的。
需要注意:如果将这个Predicate复用在多个Stream操作中,会因为共享同一个seen集合导致去重逻辑出错,但distinctByKey方法本身每次调用都会生成独立的状态载体,不会产生跨调用的状态污染。
内容的提问来源于stack exchange,提问作者phantomsee
相关产品推荐
相关产品推荐

