有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

函数式编程“展开”可选或可选。在Java流(或并行流)中返回前为空

我在这件简单的事情上遇到了麻烦。我有一个返回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,所以我不知道如何正确处理这个问题

有什么线索吗


共 (3) 个答案

  1. # 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
    }
    
  2. # 2 楼答案

    使用.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());
    }
    

    不清楚,您的原始代码应该如何工作,如果types是一个TypeB实例的列表,而getFirst()是在TypeA中声明的一个方法,正如TypeA::getFirst所指出的,但是,我认为,您明白了

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

  3. # 3 楼答案

    您可以使用^{}来“展开”内部可选文件:

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

    If a value is present, apply the provided Optional-bearing mapping function to it, return that result, otherwise return an empty Optional.