У меня есть посетитель, который возвращает универсальный тип для обеспечения гибкости в использовании:
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();
Существует ли более элегантный способфорсировать терминальную операцию в потоке?Или вы можете предложить альтернативный дизайн, который позволяет избежать этой проблемы?