【问题标题】:Filtering min of Optional values过滤可选值的最小值
【发布时间】:2020-01-28 14:33:14
【问题描述】:

我想得到一个对象列表的函数结果的最小值。 但是这个函数的返回值是可选的。 所以如果到目前为止没有设置分片时间就可以了,返回值应该是Optional.empty()

public Optional<Double> getFragmentTime(int fragment) {
    ...
}

private List<Entry> entries; // will be filled in the ctor.

public Optional<Double> getMinFragmentTime(int fragment) {
    return entries.stream()
       .map(e -> e.getFragmentTime(fragment))
       .filter(Optional::isPresent)
       .map(Optional::get)
       .min(Double::compare);
}

这是存档的正确方法吗? 两个函数调用.filter(Optional.isPresent).map(Optional.get) 对我来说似乎很奇怪,我认为必须有更好的解决方案。

【问题讨论】:

  • 好吧,您可以将filter(...).map(...) 替换为flatMap(Optional::stream) 以仅获取当前可选值的流。
  • 非常感谢,我还在学习各种不同的流方法,这似乎是一个更好的解决方案

标签: java java-8 java-stream optional


【解决方案1】:

您可以利用Optional::stream 的平面映射优势,因为 可用:

return entries.stream()                         // Stream<Entry>
        .map(e -> e.getFragmentTime(fragment))  // Stream<Optional<Double>>
        .flatMap(Optional::stream)              // Stream<Double>
        .min(Double::compare);                  // Optional<Double>

注意.min(Double.compare);的用法不正确,参数实际上是lambda表达式((d1, d2) -&gt; Double.compare(d1, d2),应缩短为方法引用Double::compare。也可以使用Comparator.comparingDouble(d -&gt; d)

如果是,您必须坚持使用.filter(Optional::isPresent).map(Optional::get)

【讨论】:

  • 是的,但是平面映射后产生的 Stream 只包含一个值。平面映射使内部结构变平。假设你有 Stream>,通过平面映射你可以实现 Stream。同样,可选的始终最多可容纳一项。 Optional::stream 返回一个空的 Stream 或带有一个元素的 Stream,该元素确保仅当前值保留在 Stream 中。如果你使用 map 而不是 flatmap,你会得到上面描述的 Stream> 并且随后调用自平面映射会导致 Stream 就像我的解决方案一样。
  • @user2622344 值得一提的是Optional.stream需要使用JDK-9及以上版本。
  • 为什么不使用单个.flatMap(e -&gt; e.getFragmentTime(fragment).stream())。除此之外,我会使用 min(Comparator.naturalOrder()) 而不是创建新的比较器。
  • 尝试尽可能多地使用方法引用似乎是一种普遍的习惯。一个典型的模式是map(Type::collectionReturningMethod) .flatMap(Collection::stream)。目前尚不清楚哪个更有效,无论如何差异很小。我倾向于假设,鉴于当前的实现,使用 lambda 的单个操作会获胜,但是,如前所述,差距很小。如果您已经在其中一个操作中使用了 lambda 表达式,那么与使用 lambda 表达式的单个操作相比,使用两个操作显然不会以任何方式获胜。
  • 这样的问题需要仔细写。例如,避免使用“什么更好”之类的内容,并强调“幕后发生的事情”或“它们在技术上有何不同”和“它如何影响性能”方面。但请注意,有an old similar Q&A,所以只有在涉及新方面时,一个新问题才会被证明是合理的,例如。更深入的技术细节(并且需要编写问题以便可以识别这种差异)。
【解决方案2】:

第一个应该使用原始类型的流,因为它很好地支持min()

public OptionalDouble getFragmentTime(int fragment) {
    ...
}

public OptionalDouble getMinFragmentTime(int fragment) {
    return entries.stream()
       .flatMap(e -> e.getFragmentTime(fragment).stream())
       .min();
}

OptionalDouble 可以传递 1 个或 0 个双精度流。 一个 flatMap 到 DoubleStream,然后取最小值。

(代码未验证。)

【讨论】:

    猜你喜欢
    • 2017-10-13
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 2015-10-17
    相关资源
    最近更新 更多