[英]Is mapToDouble() really necessary for summing a List<Double> with Java 8 streams?
據我所知,使用Java 8流對List<Double>
求和的方法是這樣的:
List<Double> vals = . . . ;
double sum = vals.stream().mapToDouble(Double::doubleValue).sum();
對我來說, mapToDouble(Double::doubleValue)
似乎有點誇張 - 只是那種lambdas和溪流應該免除的樣板“儀式”。
最佳實踐告訴我們更喜歡List
實例而不是數組,但是對於這種求和,數組似乎更清晰:
double[] vals = . . . ;
double sum = Arrays.stream(vals).sum();
當然,人們可以做到這一點:
List<Double> vals = . . . ;
double sum = vals.stream().reduce(0.0, (i,j) -> i+j);
但是reduce(....)
比sum()
長得多。
我知道這與流需要圍繞Java的非對象原語進行改造的方式有關,但是,我在這里遺漏了一些東西嗎? 有沒有辦法擠壓自動裝箱以縮短它? 或者這僅僅是當前最先進的技術?
以下是答案的摘要。 雖然我在這里有一個摘要,但我敦促讀者自己仔細閱讀答案。
@dasblinkenlight解釋說,由於Java歷史上的進一步決策,特別是在實現泛型的方式以及它們與非對象原語的關系中,因此總是需要某種拆箱。 他指出,理論上編譯器可以直接進行拆箱並允許使用簡短的代碼,但這還沒有實現。
@Holger展示了一個非常接近我所詢問的表現力的解決方案:
double sum = vals.stream().reduce(0.0, Double::sum);
我不知道新的靜態Double.sum()
方法。 添加1.8,似乎是出於我描述的目的。 我還找到了Double.min()
和Double.max()
。 展望未來,我肯定會在List<Double>
上使用這個成語進行此類操作。
有沒有辦法擠壓自動裝箱以縮短它?
就在這里。 你可以簡單地寫:
double sum = vals.stream().mapToDouble(d->d).sum();
這使得取消裝箱是隱含的,但當然不會增加效率。
由於List
已裝箱,因此拆箱是不可避免的。 另一種方法是:
double sum = vals.stream().reduce(0.0, Double::sum);
它不會執行mapToDouble
但仍允許將代碼讀作“... sum”。
對我來說,
mapToDouble(Double::doubleValue)
似乎是什么lambda和溪流應該免除。
使用mapToDouble
的需要是決定通過類型擦除實現泛型的結果,基本上關閉了在泛型中使用原語的任何可能性。 正是這一決定使得必須創建DoubleStream
, IntStream
和LongStream
類系列 - 以提供基於流的拆箱。
有沒有辦法擠壓自動裝箱以縮短它? 或者這僅僅是當前最先進的技術?
不幸的是,不是在這個時候:雖然理論上編譯器可以理解Stream<Double>
可以隱式地轉換為DoubleStream
,但是與原始文件被取消裝箱的方式相同,這還沒有完成。
就基於陣列的解決方案而言,它是三者中效率最高的解決方案。 但是,它不像其他兩個一樣靈活:使用mapToDouble
允許您對自定義類的任何屬性求和,而最后一個允許您執行其他類型的聚合。
reduce(....)
比sum()
長得多
我同意,這種方法在可讀性方面比mapToDouble
差。
這是另一種方法。 如果您只需要Double
, Integer
或Long
列表中的sum,average,min,max等,則可以使用其中一個可用的Collectors
,例如:
List<Double> doubles = Arrays.asList(3.14, 5.15, 4.12, 6.);
System.out.println(
doubles.stream()
.collect(Collectors.summingDouble(d -> d))
);
會打印18.41
注意,方法名稱是summingDouble ,還有另一個名為summarizingDouble的方法,它返回DoubleSummaryStatistics
,包含所有基本的數學運算結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.