【发布时间】:2018-11-19 01:48:16
【问题描述】:
我有一个访问者返回泛型类型以提供使用灵活性:
interface Base {
default <T> Stream<T> accept(Visitor<T> visitor) {
return visitor.visit(this).stream();
}
}
class Sub implements Base {
<T> Stream<T> accept(Visitor<T> visitor) {
return Stream.concat(super.accept(visitor), visitor.visit(this).stream());
}
}
interface Visitor<T> {
default Optional<T> visit(Base base) {
return Optional.empty()
}
default Optional<T> visit(Sub sub){
return Optional.empty()
}
}
我创建了一个访问对象流的方法:
<T> Stream<T> visitAll(Visitor<T> visitor) {
return getStream().flatMap(o -> o.accept(visitor));
}
当访问者返回一个值时,这非常有效:
visitAll(new Visitor<Sub>() {
Optional<Sub> visit(Sub sub) {
return Optional.of(sub);
}
}).forEach(...);
当它与不返回值的访问者一起使用时会出现问题:
visitAll(new Visitor<Void>() {
Optional<Void> visit(Sub sub) {
// do something with sub
return Optional.empty();
}
});
在这种情况下,流不会终止,因此访问永远不会发生。
一种可能的解决方案是强制终端操作:
<T> Stream<T> visitAll(Visitor<T> visitor) {
return getStream()
.collect(Collectors.toList()).stream()
.flatMap(o -> o.accept(visitor));
}
另一种解决方案是始终使用该值:
visitAll(new Visitor<Void>() {
Optional<Void> visit(Sub sub) {
// do something with sub
return Optional.empty();
}
}).findAny();
有没有更优雅的方式来强制对流进行终端操作?或者您是否可以提出替代设计来避免该问题?
【问题讨论】:
-
我认为让
visit()首先返回一个流是错误的。它违反了访问者必须访问对象的期望。返回一个列表,让客户端根据需要进行流式传输。 -
@shmosel 这是一个很好的建议 - 谢谢。我唯一担心的是在通过的过程中会创建很多列表对象。虽然我想我不应该认为这比这个解决方案中创建的所有流更糟糕!我会试一试,但也有兴趣看看是否有其他建议。
-
visitor.visit(this)返回Optional<T>,你能告诉我你是如何从Optional<T>生成Stream<T>的吗?visitor.visit(this).stream();是错误的。 -
@Nikolas Optional 从 JDK9 开始具有流方法。查看Optional<T> 类
-
@Aominè:好吧,我不了解java-9。我添加标签。
标签: java java-stream optional java-9