“Unwrap”在Java流(或并行流)中返回之前可选的Optional.empty

时间:2017-01-09 21:15:47

标签: java functional-programming java-stream

我遇到这个简单的事情有困难。我有一个方法返回Optional<TypeA>

public Optional<TypeA> getFirst() {
  return set.stream().filter(it -> it.getStatus() == SUCCESS).findFirst(); // set is a Set<TypeA>
}

...然后我从以下地方打电话:

public boolean hasFirst() {
  return types.parallelStream() // types is a List<TypeB> that has a Set<TypeA>
    .filter(it -> it.getTotalAmount() > 0)
    .map(TypeA::getFirst)
    .findFirst() // this can return an Optional[Optional.empty]
    .isPresent();
}

问题是,OptionalOptional正在按预期返回true,所以我不知道如何正确使用这个!{/ p>

任何线索?

3 个答案:

答案 0 :(得分:3)

您可以使用Optional#flatMap来解开&#39;内在的选择:

public boolean hasFirst() {
   return types.parallelStream()
       .filter(it -> it.getTotalAmount() > 0)
       .map(TypeA::getFirst)
       .findFirst() // return Optional[Optional.empty]
       .flatMap(i -> i) // <---
       .isPresent(); // true
}
  

如果存在值,则将提供的Optional-bearing映射函数应用于该函数,返回该结果,否则返回空的Optional。

答案 1 :(得分:3)

使用.findFirst().isPresent()是一种常见的反模式。如果您只想知道是否匹配,如果您打算使用并行流,则无需询问第一个尤其是,其中对于第一场比赛而不是任何比赛可能会有明显的性能缺陷。所以findAny会更受欢迎,但是当你只想知道是否匹配时,没有必要要求一个价值:

public boolean hasFirst() {
  return types.parallelStream() // types is a List<TypeB> that has a Set<TypeA>
    .filter(it -> it.getTotalAmount() > 0)
    .anyMatch(obj -> obj.getFirst().isPresent());
}

目前尚不清楚,如果typesTypeB个实例的列表,而getFirst()TypeA中声明的方法,原始代码应该如何工作, TypeA::getFirst表示,但是,我想,你得到的照片......

我建议您还将方法hasFirst()重命名为hasAny()。当然,具有任何匹配元素的集合也将具有第一个,但是关注“第一”的集合会产生误导,特别是因为TypeA元素是在Set中,这通常意味着根本没有定义的顺序。

答案 2 :(得分:1)

要将Optional<Optional<Foo>>折叠为Optional<Foo>,您可以使用orElse,因此:

Optional<Optional<Integer>> opt = Optional.of(Optional.empty()); // Your case
Optional<Integer> collapsedOpt = opt.orElse(Optional.empty()); // Will be empty if original is empty or Optional.of(empty).

因此,对于您的示例,您可以在流调用中添加.orElse:

public boolean hasFirst() {
  return types.parallelStream()
    .filter(it -> it.getTotalAmount() > 0)
    .map(TypeA::getFirst)
    .findFirst() // return Optional[Optional.empty]
    .orElse(Optional.empty()) // Now Optional.empty if was originally empty
    .isPresent(); // true
}