我有一个访问者,它返回一个泛型类型以提供灵活性:
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();
有没有更优雅的方法来强制流上的终端操作?或者有没有其他的设计可以避免这个问题?