可选流到可选流的 Java 流

Nie*_*Nic 3 java functional-programming

我需要转换Stream<Optional<Integer>>Optional<Stream<Integer>>.

Optional<Stream<Integer>>当至少有一个值为空时,输出应为空值Stream<Optional<Integer>>

您知道解决问题的任何功能方法吗?我尝试使用collect方法,但没有成功。

Rad*_*def 5

好吧,这里的棘手之处在于,如果您只获得了一个Stream,则您只能使用它一次。

要无状态并避免冗余复制,一种方法是捕获NoSuchElementException

static <T> Optional<Stream<T>> invert(Stream<Optional<T>> stream) {
    try {
        return Optional.of(
            stream.map(Optional::get)
                  .collect(Collectors.toList())
                  .stream());
    } catch (NoSuchElementException e) {
        return Optional.empty();
    }
}
Run Code Online (Sandbox Code Playgroud)

一个简单的反转是:

static <T> Optional<Stream<T>> invert(Stream<Optional<T>> stream) {
    return Optional.of(stream.map(Optional::get));
}
Run Code Online (Sandbox Code Playgroud)

但是要确定它是否包含一个空元素,您需要实际遍历它并消耗它。

如果您获得了流的来源,则可以在不收集的情况下遍历它:

static <T> Optional<Stream<T>> invert(
        Supplier<Stream<Optional<T>>> supplier) {
    // taking advantage of short-circuiting here
    // instead of allMatch(Optional::isPresent)
    return supplier.get().anyMatch(o -> !o.isPresent()) ?
        Optional.empty() : Optional.of(supplier.get().map(Optional::get));
}
Run Code Online (Sandbox Code Playgroud)
List<Optional<Integer>> myInts =
    Arrays.asList(Optional.of(1), Optional.of(2), Optional.of(3));
Optional<Stream<Integer>> inverted = invert(myInts::stream);
Run Code Online (Sandbox Code Playgroud)

这可能是一种更有趣的方法。(但它很容易出现竞争条件,因为stream()取了两次。如果其他线程在两者之间添加了一个空元素并逃脱了它,我们就会遇到问题。)