Java 8 Java8中谓词如何维护状态
我正在看这篇文章,并试图理解下面的代码 抄袭斯图尔特·马克斯的答案Java 8 Java8中谓词如何维护状态,java-8,java-stream,Java 8,Java Stream,我正在看这篇文章,并试图理解下面的代码 抄袭斯图尔特·马克斯的答案 public static Predicate distinctByKey(函数因为这是一个捕获lambda,实际上每次调用distinctByKey时都会返回一个新的Predicate实例;但这会发生在整个流中,而不是每个单独的元素 如果您愿意以以下方式运行示例: Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here 您将看到为您的谓词的实现生成了一个类。因为这是一个有状态
public static Predicate distinctByKey(函数因为这是一个捕获lambda,实际上每次调用distinctByKey
时都会返回一个新的Predicate
实例;但这会发生在整个流中,而不是每个单独的元素
如果您愿意以以下方式运行示例:
Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
您将看到为您的谓词的实现生成了一个类
。因为这是一个有状态lambda-它捕获CHM
和函数
,它将有一个私有
构造函数和一个返回实例的静态工厂方法
对distinctByKey
的每次调用都将生成不同的实例,但该实例将被流的每个元素重用。如果运行此示例,事情可能会更明显:
public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
Predicate<T> predicate = t -> {
Object obj = keyExtractor.apply(t);
System.out.println("stream element : " + obj);
return seen.putIfAbsent(obj, Boolean.TRUE) == null;
};
System.out.println("Predicate with hash :" + predicate.hashCode());
return predicate;
}
@Getter
@AllArgsConstructor
static class User {
private final String name;
}
public static void main(String[] args) {
Stream.of(new User("a"), new User("b"))
.filter(distinctByKey(User::getName))
.collect(Collectors.toList());
}
流的两个元素都有一个谓词
如果添加另一个过滤器
:
Stream.of(new User("a"), new User("b"))
.filter(distinctByKey(User::getName))
.filter(distinctByKey(User::getName))
.collect(Collectors.toList());
将有两个谓词
s:
Predicate with hash :1259475182
Predicate with hash :1072591677
stream element : a
stream element : a
stream element : b
stream element : b
这看起来很混乱,但很简单。实际发生的是,distinctByKey
方法只被调用一次,因此只有一个ConcurrentHashMap
的实例被lambda表达式捕获。因此当distinctByKey
方法返回一个谓词时ct然后我们将其应用于流的每个元素。对于parallelStream(),这是真的吗?@xyz:不要被流的使用这一事实所迷惑。只需看看代码结构。您有a().b(c()).d().e()
,因此方法的调用顺序是a
,c
,b
(接收c
的结果),d
,e
。a
方法是stream
,c
方法是distinctByKey
,b
方法是filter
,等等,但实际的流操作只从e
开始,即reduce
。其他四个方法在此之前已经被调用并完成。@xyz同样适用。@Aominè确实,该方法只会被调用一次,但会有多个谓词的实例returned@Aominè不用担心-当您想到只调用一次get的bootstrap方法时,它会变得更加有趣,一个调用站点
,它将方法句柄
包装到get$Lambda
me通过ASM
只链接一次的方法构建,每个流元素有多少不同谓词实例的细节是疯狂的?不,每次调用distinctByKey
@StuartMarks都有一个CHM和一个谓词,调用它时@StuartMarks不会获取$Lambda
始终返回一个新谓词?当然,但是获取$Lambda()
只应在计算lambda表达式时调用,即从调用distinctByKey
的内部调用。通过筛选器的每个流元素将调用同一lambda实例的test()
方法。正是该实例保存捕获的CHM和keyExtractor函数。
Stream.of(new User("a"), new User("b"))
.filter(distinctByKey(User::getName))
.filter(distinctByKey(User::getName))
.collect(Collectors.toList());
Predicate with hash :1259475182
Predicate with hash :1072591677
stream element : a
stream element : a
stream element : b
stream element : b