私が知る限り、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の非オブジェクトプリミティブの周りにストリームを後付けする方法に関係していると思いますが、それでも、ここで何かが欠けていますか?これを短くするためにオートボクシングを絞る方法はありますか?または、これは単なる最新技術ですか?
以下に回答の要約を示します。ここに要約がありますが、読者自身に回答そのものを熟読することをお勧めします。
@dasblinkenlightは、特にジェネリックが実装された方法と非オブジェクトプリミティブとの関係において、Javaの歴史の中でさらに決定が下されるため、何らかの種類のボックス化解除が常に必要になると説明しています。彼は、コンパイラがボックス化解除を直観し、より簡潔なコードを許可することは理論的には可能であると指摘しているが、これはまだ実装されていない。
@Holgerは、私が尋ねていた表現力に非常に近い解決策を示しています。
_double sum = vals.stream().reduce(0.0, Double::sum);
_
私は新しい静的Double.sum()
メソッドを知りませんでした。 1.8で追加された、それは私が説明していたまさにその目的のために意図されているようです。 Double.min()
とDouble.max()
も見つかりました。今後、このようなイディオムを_List<Double>
_などの操作に使用します。
私には、
mapToDouble(Double::doubleValue)
は[何]のラムダとストリームが不要であると思われます。
mapToDouble
を使用する必要があるのは、型消去を介してジェネリックを実装するという決定の結果であり、ジェネリック内でプリミティブを使用する可能性がある場合は基本的にドアを閉じます。同じ決定により、クラスのDoubleStream
、IntStream
、およびLongStream
ファミリーを作成する必要が生じました。これは、ストリームベースのボックス化解除を提供するためです。
これを短くするためにオートボクシングを絞る方法はありますか?または、これは単なる最新技術ですか?
残念ながら、現時点ではありません:コンパイラが_Stream<Double>
_を暗黙的にDoubleStream
に変換できることを理論的に理解することは可能ですが、プリミティブがボックス化されていないのと同じですできた。
アレイベースのソリューションに関する限り、3つのソリューションの中で最も効率的です。ただし、他の2つほど柔軟ではありません。mapToDouble
を使用するとカスタムクラスの属性を合計でき、最後の1つでは他のタイプの集計を実行できます。
reduce(....)
はsum()
よりもずっと長い
私は同意します、このアプローチは読みやすさの点でmapToDouble
より悪いです。
これを短くするためにオートボクシングを絞る方法はありますか?
はいあります。あなたは単に書くことができます:
double sum = vals.stream().mapToDouble(d->d).sum();
これにより、ボックス化解除が暗黙的になりますが、もちろん、効率は向上しません。
List
isはボックス化されているため、ボックス化解除は避けられません。別のアプローチは次のとおりです。
double sum = vals.stream().reduce(0.0, Double::sum);
mapToDouble
は実行しませんが、コードを「…sum」として読み取ることができます。
別の方法があります。 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))
);
18.41を出力します
メソッド名はsummingDoubleであることに注意してください。summarizingDoubleと呼ばれる別のメソッドがあり、DoubleSummaryStatistics
を返し、すべての基本的な数学演算結果を含みます。