mapToDouble()是否真的需要将List <Double>与Java 8流相加?

spa*_*ead 65 java java-8 java-stream

据我所知,List<Double>使用Java 8流总结的方法是这样的:

List<Double> vals = . . . ;
double sum = vals.stream().mapToDouble(Double::doubleValue).sum();
Run Code Online (Sandbox Code Playgroud)

对我来说,这mapToDouble(Double::doubleValue)似乎是一种狡猾 - 只是那种lambdas和溪流应该免除的样板"仪式".

最佳实践告诉我们更喜欢List实例而不是数组,但是对于这种求和,数组似乎更清晰:

double[] vals = . . . ;
double sum = Arrays.stream(vals).sum();
Run Code Online (Sandbox Code Playgroud)

当然,人们可以这样做:

List<Double> vals = . . . ;
double sum = vals.stream().reduce(0.0, (i,j) -> i+j);
Run Code Online (Sandbox Code Playgroud)

但那reduce(....)比这长得多sum().

我知道这与流需要围绕Java的非对象原语进行改造的方式有关,但是,我在这里遗漏了一些东西吗?有没有办法挤压自动装箱以缩短它?或者这仅仅是当前最先进的技术?


更新 - 答案摘要

以下是答案的摘要.虽然我在这里有一个摘要,但我敦促读者自己仔细阅读答案.

@dasblinkenlight解释说,由于Java历史上的进一步决策,特别是在实现泛型的方式以及它们与非对象原语的关系中,因此总是需要某种拆箱.他指出,理论上编译器可以直接进行拆箱并允许使用简短的代码,但这还没有实现.

@Holger展示了一个非常接近我所询问的表现力的解决方案:

double sum = vals.stream().reduce(0.0, Double::sum);
Run Code Online (Sandbox Code Playgroud)

我不知道新的静态Double.sum()方法.添加1.8,似乎是出于我描述的目的.我也发现了Double.min()Double.max().展望未来,我肯定会使用这个成语来进行类似的操作List<Double>.

Hol*_*ger 47

有没有办法挤压自动装箱以缩短它?

就在这里.你可以简单地写:

double sum = vals.stream().mapToDouble(d->d).sum();
Run Code Online (Sandbox Code Playgroud)

这使得取消装箱是隐含的,但当然不会增加效率.

由于List 装箱,拆箱是不可避免的.另一种方法是:

double sum = vals.stream().reduce(0.0, Double::sum);
Run Code Online (Sandbox Code Playgroud)

它没有做mapToDouble但仍允许将代码读作"... sum".

  • 很好 - 我非常喜欢第二个 - 谢谢!我不知道`Double` 上的新`sum()` 方法。 (2认同)

das*_*ght 31

对我来说,mapToDouble(Double::doubleValue)似乎[什么] lambdas和溪流应该放弃.

使用的需要mapToDouble是决定通过类型擦除来实现泛型的结果,基本上关闭了在泛型中使用原语的任何可能性.这是使得有必要创建相同的决定DoubleStream,IntStreamLongStream家庭类-提供基于流的拆箱.

有没有办法挤压自动装箱以缩短它?或者这仅仅是当前最先进的技术?

不幸的是,现在不是这样:虽然理论上编译器Stream<Double>可以确定可以DoubleStream隐式转换,但是原始方法是未装箱的,但这还没有完成.

就基于阵列的解决方案而言,它是三者中效率最高的解决方案.但是,它不像其他两个那样灵活:一个mapToDouble允许您对自定义类的任何属性求和,而最后一个允许您执行其他类型的聚合.

reduce(....) 比...长得多 sum()

我同意,这种方法比mapToDouble可读性更差.

  • 我真的很期待Project Valhalla,http://mail.openjdk.java.net/pipermail/discuss/2014-June/003445.html (3认同)

jFr*_*tic 5

这是另一种方法.如果您只需要列表中的总和,平均值,最小值,最大值等Double,Integer或者Long,您可以使用其中一个Collectors,例如:

List<Double> doubles = Arrays.asList(3.14, 5.15, 4.12, 6.);
System.out.println(
        doubles.stream()
                .collect(Collectors.summingDouble(d -> d))
);
Run Code Online (Sandbox Code Playgroud)

会打印18.41

注意,方法名称是summingDouble,还有另一个名为summarizingDouble的方法,它返回DoubleSummaryStatistics包含所有基本数学运算结果.