如何从Optional <t>列表中获取第一个非空Optional <t>

时间:2015-06-17 01:41:40

标签: lambda functional-programming java-8

我正在将一些代码移动到java8,尝试(有时强迫自己)使用stream和lambdas,我对它们感到不舒服。

我在类中有一些验证业务对象的方法。每个方法都是

Optional<Fail> validate1(BusinessObject bo)

其中Fail是以某种方式描述错误的枚举,如果没有错误,则该方法返回Optional.empty()。我不需要收集所有错误,但返回第一个错误,而不执行以下验证。

我正在做的是

//first convert methods to suppliers
Supplier<Optional<Fail>> validate1= () -> validate1(bo);
Supplier<Optional<Fail>> validate2= () -> validate2(bo);
Supplier<Optional<Fail>> validate3= () -> validate3(bo);
//then some stream magic
return Stream.of(validate1, validate2, validate3)
    .map(Supplier::get)
    .filter(f -> f.isPresent())
    .findFirst()
    .orElse(Optional.empty()); //without the orElse, no error would return
                                         // Optional(Optional.empty()) 
                                         // instead of Optional.empty()

它有效,它完成工作,它不执行不必要的方法,它是清晰的(如果Optional.orElse被命名为getOrElse,它会更清晰,但这是我无法实现的)。我想要找出的是,如果这是一个合理的方式来做我想要的,如果这个代码被认为是'好风格'或'惯用java8',或者我误用Stream或Optional,或者遗漏了一些明显的东西。

返回第一个非空的可选或者一个空的可选,如果它们都是空的,看起来很通常认为有一个正式的方法可以做到这一点,我脑子里的东西是大喊“Monads!”,但是我对Haskell的无知几乎是完美的,所以我不知道。

1 个答案:

答案 0 :(得分:2)

Optional很像Stream,其中包含0或1个元素。但它没有实现Stream,也没有stream()方法(就像集合一样)。

但是,将Optional<T>转换为Stream<T>并不困难,此功能可以实现:

public static <T> Function<Optional<? extends T>, Stream<T>> asStream() {
    return op -> op.map(Stream::of).orElseGet(Stream::empty);
}

使用该方法,您只需使用flatMap:

Stream.of(validate1, validate2, validate3)
        .map(Supplier::get)
        .flatMap(asStream())
        .findFirst();