强制终端操作

时间:2018-06-09 01:28:09

标签: java java-stream optional java-9

我有一个访问者返回一个通用类型以提供使用灵活性:

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();

是否有更优雅的方法来强制终端操作?或者是否有可以建议的替代设计可以避免这个问题?

1 个答案:

答案 0 :(得分:0)

我会创建两个版本的visitAll,一个返回一个流,一个终止流并且不返回任何内容。

<T> Stream<T> visitAllStream(Visitor<T> visitor) {
    return getStream().flatMap(o -> o.accept(visitor));
}

void visitAll(Visitor<?> visitor) {
    getStream().forEach(o -> o.accept(visitor));
}

这样,当您要对结果进行进一步操作时,您只能使用visitAllStream。您仍然必须确保在visitAllStream visitAll时不要使用{{1}},但这会使错误变得更加明显。