【问题标题】:Convert OptionalDouble to Optional <java.lang.Double>将 OptionalDouble 转换为可选 <java.lang.Double>
【发布时间】:2017-07-01 20:16:16
【问题描述】:

我有一个构建列表的方法,我希望它以可选值的形式返回列表的平均值。

但是,当我使用 Java 8 计算平均值时,我总是将返回值作为 OptionalDouble。

如何转换

OptionalDouble to Optional<Double>?

以下是我的平均计算代码:

private static Optional<Double> averageListValue() {
     // Build list
     List<Double> testList = new ArrayList<>();
     testList.add(...);
     ...
     ...


     return testList.stream().mapToDouble(value -> value).average();
}

谢谢。

【问题讨论】:

  • OptionalDouble 上的getAsDouble 怎么样,这将为您提供double 的平均值,这是您最终想要的。
  • 一个 OptionalDouble 更有效;更接近double,因此将使用代码从Optional&lt;Double&gt; 转换为OptionalDouble 似乎更好。但是,我想你知道这一点并且有你的理由。
  • 如果代码构建了一个如图所示的列表,您已经知道它永远不会为空。那么为什么要返回 Optional 呢?
  • @VHS 感谢您的建议。显然这种方法在这里也达成了共识。
  • @JoopEggen 感谢您的信息。是的,我有我的理由......

标签: java java-8 average optional


【解决方案1】:

我不知道是否存在一个简洁的解决方案,但应该可以:

OptionalDouble optionalDouble = testList.stream().mapToDouble(value -> value).average();
return Optional.ofNullable(optionalDouble.isPresent() ? optionalDouble.getAsDouble() : null);

【讨论】:

    【解决方案2】:

    只是为了好玩,我想看看它是否可以写在一条语句中,而不需要 OptionalDouble 临时变量。这是我想出的最好的:

    return testList.stream().collect(Collectors.collectingAndThen(
        Collectors.summarizingDouble(Double::doubleValue),
        stat -> Optional.ofNullable(stat.getCount()>0 ? stat.getAverage() : null)));
    

    【讨论】:

      【解决方案3】:

      我来到了这个“一行”(单语句)解决方案:

          return ((Function<OptionalDouble, Optional<Double>>) od
                  -> od.isPresent() ? Optional.of(od.getAsDouble()) : Optional.empty())
                  .apply(testList.stream().mapToDouble(v -> v).average());
      

      顺便说一句,只是为了极简主义,如果您要进行静态导入:

      import static java.util.Optional.*;
      

      你可以省略Optional.,这让它不那么凌乱了。

      【讨论】:

        【解决方案4】:

        我会采用这种方法:

        private static Optional<Double> convert(OptionalDouble od) {
            return od.isPresent() ? 
                Optional.of(od.getAsDouble()) : Optional.empty();
        }
        

        【讨论】:

          【解决方案5】:

          顺便说一句,我找到了另一个解决方案,它具有最简单的形式。

          我已经开始思考:平均结果什么时候可以为空?只有当列表本身为空时,对吗?因此,如果我们确定该列表不为空,那么我们可以安全地执行getAsDouble()

          return Optional.ofNullable(testList.isEmpty() ? null : 
                  testList.stream().mapToDouble(v -> v).average().getAsDouble())
          

          (从性能的角度来看,这可能比创建额外的 lambda 包装器更有效,正如在类似答案中所建议的那样。)

          【讨论】:

          • 这是一个双重测试,首先是 isEmpty(),然后是 null 内的 ofNullable 测试。不需要第二次测试:return testList.isEmpty()? Optional.empty(): Optional.of(testList.stream().mapToDouble(v -&gt; v).average().getAsDouble());
          • 我想过,但是我特意把三元运算放在Optional.ofNullable里面。它更时尚,而我同意它还有一个比较操作
          【解决方案6】:

          @Andremoniy's answer 的一个细微变化是跳过DoubleStream 并使用averagingDouble() 收集器:

          if (testList.isEmpty()) {
              return Optional.empty();
          }
          return Optional.of(testList.stream().collect(Collector.averagingDouble()));
          

          或者考虑 0 是否是空列表的有效返回值,并可能完全跳过 Optional

          【讨论】:

            【解决方案7】:

            这是一个很老的问题,但在较新版本的 Java 中,您可以:

            // Given an OptionalDouble
            var myOptionalDouble = OptionalDouble.of(3.0d);
            
            // Convert to Optional<Double>
            var myOptional = myOptionalDouble.stream().boxed().findFirst();
            

            反过来也同样简单:

            var myOptional = Optional.of(Double.valueOf(3.0d));
            
            var myOptionalDouble = myOptional.stream().mapToDouble(t -> t).findFirst();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-10-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-10-02
              • 1970-01-01
              相关资源
              最近更新 更多