在流中找到第一个<Optional<T>>
findFirst on a Stream<Optional<T>>
假设您有一个 Optional<T>
流,您想要在(如果存在)上触发 Consumer<T>
。
最优雅的处理方式是什么?
我可以通过 Optional::isPresent
过滤和 Optional::isGet
映射来管理,但这似乎 "hacky" 而不是 Optional
的精神:
Stream.of(a, b, c, d)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.ifPresent(s -> System.out.println("This was cumbersome: " + s));
我同意这很麻烦,但它可能是最直接的解决方案,而且不会变得更加复杂。
我在类似情况下做过的一件事是创建一种方法将 Optional
变成 Stream
:
private Stream<T> optionalStream(Optional<T> optional) {
if (optional.isPresent())
return Stream.of(optional.get());
else
return Stream.empty());
}
所以你可以使用 flatMap
:
Stream.of(a, b, c, d)
.flatMap(this::optionalStream).findFirst()...
当我第一次看到 Optional
时,我想知道为什么他们没有包含 stream
方法来执行此操作。更新:Java 9 将包含 Optional
.
的这种方法
但老实说,我不确定这是否比您 filter
然后 map
的解决方案简单得多。
我不确定下面的任何一种方法是否比你的更好...
首先,您可以尝试 reduce()
:
Stream.of(a, b, c, d).reduce(Optional.empty(), (o1, o2) -> o1.isPresent() ? o1 : o2)
.ifPresent(s -> System.out.println("This seems cumbersome as well: " + s));
您仍然会查询 Optional
,尽管这会在减少流时发生。
一种更优雅的方法(尽管不那么冗长)是使用专门的 Consumer
,它仅在非空时才接受 Optional
的值。为此,您需要按如下方式定义 OptionalConsumer
:
@FunctionalInterface
interface OptionalConsumer<T>
extends Consumer<Optional<T>> {
@Override
default void accept(Optional<T> o) {
if (o.isPresent()) {
this.acceptIfPresent(o.get());
}
}
void acceptIfPresent(T o);
static <U> OptionalConsumer<U> of(Consumer<U> c) {
return c::accept;
}
}
您可以这样使用它:
Stream.of(a, b, c, d).forEach(OptionalConsumer.of(s -> System.out.println("Better? " + s)));
备注:
- 当您需要在许多不同的流中执行相同的逻辑时,也许这种方法更好。
- 我不敢打赌它在并行流上运行良好。
- 由于
OptionalConsumer
实际上是一个 Consumer
,我不知道如何将它与 findFirst()
一起使用。
我认为 flatMap 在这里非常方便
Stream.of(a, b, c, d)
.flatMap(opt -> opt.map(Stream::of).orElse(Stream.empty()))
.findFirst()
.ifPresent(s -> System.out.println("This was cumbersome: " + s));
不理想,但至少简洁。
假设您有一个 Optional<T>
流,您想要在(如果存在)上触发 Consumer<T>
。
最优雅的处理方式是什么?
我可以通过 Optional::isPresent
过滤和 Optional::isGet
映射来管理,但这似乎 "hacky" 而不是 Optional
的精神:
Stream.of(a, b, c, d)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.ifPresent(s -> System.out.println("This was cumbersome: " + s));
我同意这很麻烦,但它可能是最直接的解决方案,而且不会变得更加复杂。
我在类似情况下做过的一件事是创建一种方法将 Optional
变成 Stream
:
private Stream<T> optionalStream(Optional<T> optional) {
if (optional.isPresent())
return Stream.of(optional.get());
else
return Stream.empty());
}
所以你可以使用 flatMap
:
Stream.of(a, b, c, d)
.flatMap(this::optionalStream).findFirst()...
当我第一次看到 Optional
时,我想知道为什么他们没有包含 stream
方法来执行此操作。更新:Java 9 将包含 Optional
.
但老实说,我不确定这是否比您 filter
然后 map
的解决方案简单得多。
我不确定下面的任何一种方法是否比你的更好...
首先,您可以尝试 reduce()
:
Stream.of(a, b, c, d).reduce(Optional.empty(), (o1, o2) -> o1.isPresent() ? o1 : o2)
.ifPresent(s -> System.out.println("This seems cumbersome as well: " + s));
您仍然会查询 Optional
,尽管这会在减少流时发生。
一种更优雅的方法(尽管不那么冗长)是使用专门的 Consumer
,它仅在非空时才接受 Optional
的值。为此,您需要按如下方式定义 OptionalConsumer
:
@FunctionalInterface
interface OptionalConsumer<T>
extends Consumer<Optional<T>> {
@Override
default void accept(Optional<T> o) {
if (o.isPresent()) {
this.acceptIfPresent(o.get());
}
}
void acceptIfPresent(T o);
static <U> OptionalConsumer<U> of(Consumer<U> c) {
return c::accept;
}
}
您可以这样使用它:
Stream.of(a, b, c, d).forEach(OptionalConsumer.of(s -> System.out.println("Better? " + s)));
备注:
- 当您需要在许多不同的流中执行相同的逻辑时,也许这种方法更好。
- 我不敢打赌它在并行流上运行良好。
- 由于
OptionalConsumer
实际上是一个Consumer
,我不知道如何将它与findFirst()
一起使用。
我认为 flatMap 在这里非常方便
Stream.of(a, b, c, d)
.flatMap(opt -> opt.map(Stream::of).orElse(Stream.empty()))
.findFirst()
.ifPresent(s -> System.out.println("This was cumbersome: " + s));
不理想,但至少简洁。