web-dev-qa-db-ja.com

Java 8ストリームでList <Double>を合計するためにmapToDouble()は本当に必要ですか?

私が知る限り、Java 8ストリームを使用して_List<Double>_を合計する方法は次のとおりです。

_List<Double> vals = . . . ;
double sum = vals.stream().mapToDouble(Double::doubleValue).sum();
_

私には、mapToDouble(Double::doubleValue)は一種の無愛想なように見えます-ラムダとストリームが不要な定型的な「儀式」のようなものです。

ベストプラクティスでは、配列よりも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の非オブジェクトプリミティブの周りにストリームを後付けする方法に関係していると思いますが、それでも、ここで何かが欠けていますか?これを短くするためにオートボクシングを絞る方法はありますか?または、これは単なる最新技術ですか?


更新-Answers Digest

以下に回答の要約を示します。ここに要約がありますが、読者自身に回答そのものを熟読することをお勧めします。

@dasblinkenlightは、特にジェネリックが実装された方法と非オブジェクトプリミティブとの関係において、Javaの歴史の中でさらに決定が下されるため、何らかの種類のボックス化解除が常に必要になると説明しています。彼は、コンパイラがボックス化解除を直観し、より簡潔なコードを許可することは理論的には可能であると指摘しているが、これはまだ実装されていない。

@Holgerは、私が尋ねていた表現力に非常に近い解決策を示しています。

_double sum = vals.stream().reduce(0.0, Double::sum);
_

私は新しい静的Double.sum()メソッドを知りませんでした。 1.8で追加された、それは私が説明していたまさにその目的のために意図されているようです。 Double.min()Double.max()も見つかりました。今後、このようなイディオムを_List<Double>_などの操作に使用します。

65
sparc_spread

私には、mapToDouble(Double::doubleValue)は[何]のラムダとストリームが不要であると思われます。

mapToDoubleを使用する必要があるのは、型消去を介してジェネリックを実装するという決定の結果であり、ジェネリック内でプリミティブを使用する可能性がある場合は基本的にドアを閉じます。同じ決定により、クラスのDoubleStreamIntStream、およびLongStreamファミリーを作成する必要が生じました。これは、ストリームベースのボックス化解除を提供するためです。

これを短くするためにオートボクシングを絞る方法はありますか?または、これは単なる最新技術ですか?

残念ながら、現時点ではありません:コンパイラが_Stream<Double>_を暗黙的にDoubleStreamに変換できることを理論的に理解することは可能ですが、プリミティブがボックス化されていないのと同じですできた。

アレイベースのソリューションに関する限り、3つのソリューションの中で最も効率的です。ただし、他の2つほど柔軟ではありません。mapToDoubleを使用するとカスタムクラスの属性を合計でき、最後の1つでは他のタイプの集計を実行できます。

reduce(....)sum()よりもずっと長い

私は同意します、このアプローチは読みやすさの点でmapToDoubleより悪いです。

31
dasblinkenlight

これを短くするためにオートボクシングを絞る方法はありますか?

はいあります。あなたは単に書くことができます:

double sum = vals.stream().mapToDouble(d->d).sum();

これにより、ボックス化解除が暗黙的になりますが、もちろん、効率は向上しません。

Listisはボックス化されているため、ボックス化解除は避けられません。別のアプローチは次のとおりです。

double sum = vals.stream().reduce(0.0, Double::sum);

mapToDoubleは実行しませんが、コードを「…sum」として読み取ることができます。

47
Holger

別の方法があります。 DoubleInteger、またはLongのリストで合計、平均、最小、最大などが必要な場合は、使用可能な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を返し、すべての基本的な数学演算結果を含みます。

5
jFrenetic