[解決済み】ストリームを使ったBigDecimalsの足し算について
質問
BigDecimalsのコレクションを持っています(この例では
LinkedList
を追加したいのですが。このような場合、ストリームを使用することは可能ですか?
に気がつきました。
Stream
クラスにはいくつかのメソッドがあります。
Stream::mapToInt
Stream::mapToDouble
Stream::mapToLong
それぞれ、便利な
sum()
メソッドを使用します。しかし、ご存知のように
float
と
double
の演算は、ほとんどの場合、悪い考えです。
では、BigDecimalsを合計する便利な方法はないのでしょうか?
これは、私がこれまでに持っているコードです。
public static void main(String[] args) {
LinkedList<BigDecimal> values = new LinkedList<>();
values.add(BigDecimal.valueOf(.1));
values.add(BigDecimal.valueOf(1.1));
values.add(BigDecimal.valueOf(2.1));
values.add(BigDecimal.valueOf(.1));
// Classical Java approach
BigDecimal sum = BigDecimal.ZERO;
for(BigDecimal value : values) {
System.out.println(value);
sum = sum.add(value);
}
System.out.println("Sum = " + sum);
// Java 8 approach
values.forEach((value) -> System.out.println(value));
System.out.println("Sum = " + values.stream().mapToDouble(BigDecimal::doubleValue).sum());
System.out.println(values.stream().mapToDouble(BigDecimal::doubleValue).summaryStatistics().toString());
}
見ての通り、BigDecimals を使って合計しています。
BigDecimal::doubleValue()
しかし、これは(予想通り)正確ではありません。
回答後の編集で後世に残す。
どちらの回答も大変参考になりました。少し付け加えると、私の現実のシナリオでは、生の
BigDecimal
を、インボイスで包む。しかし、Aman Agnihotri氏の回答を修正し、この点を考慮するために
map()
関数を使用することができます。
public static void main(String[] args) {
LinkedList<Invoice> invoices = new LinkedList<>();
invoices.add(new Invoice("C1", "I-001", BigDecimal.valueOf(.1), BigDecimal.valueOf(10)));
invoices.add(new Invoice("C2", "I-002", BigDecimal.valueOf(.7), BigDecimal.valueOf(13)));
invoices.add(new Invoice("C3", "I-003", BigDecimal.valueOf(2.3), BigDecimal.valueOf(8)));
invoices.add(new Invoice("C4", "I-004", BigDecimal.valueOf(1.2), BigDecimal.valueOf(7)));
// Classical Java approach
BigDecimal sum = BigDecimal.ZERO;
for(Invoice invoice : invoices) {
BigDecimal total = invoice.unit_price.multiply(invoice.quantity);
System.out.println(total);
sum = sum.add(total);
}
System.out.println("Sum = " + sum);
// Java 8 approach
invoices.forEach((invoice) -> System.out.println(invoice.total()));
System.out.println("Sum = " + invoices.stream().map((x) -> x.total()).reduce((x, y) -> x.add(y)).get());
}
static class Invoice {
String company;
String invoice_number;
BigDecimal unit_price;
BigDecimal quantity;
public Invoice() {
unit_price = BigDecimal.ZERO;
quantity = BigDecimal.ZERO;
}
public Invoice(String company, String invoice_number, BigDecimal unit_price, BigDecimal quantity) {
this.company = company;
this.invoice_number = invoice_number;
this.unit_price = unit_price;
this.quantity = quantity;
}
public BigDecimal total() {
return unit_price.multiply(quantity);
}
public void setUnit_price(BigDecimal unit_price) {
this.unit_price = unit_price;
}
public void setQuantity(BigDecimal quantity) {
this.quantity = quantity;
}
public void setInvoice_number(String invoice_number) {
this.invoice_number = invoice_number;
}
public void setCompany(String company) {
this.company = company;
}
public BigDecimal getUnit_price() {
return unit_price;
}
public BigDecimal getQuantity() {
return quantity;
}
public String getInvoice_number() {
return invoice_number;
}
public String getCompany() {
return company;
}
}
解決方法は?
オリジナルの回答
はい、可能です。
List<BigDecimal> bdList = new ArrayList<>();
//populate list
BigDecimal result = bdList.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
何をするかというと
-
を取得する。
List<BigDecimal>
. -
に変えます。
Stream<BigDecimal>
-
reduceメソッドを呼び出す。
3.1. 加算のためのID値、すなわち
BigDecimal.ZERO
.3.2. を指定しています。
BinaryOperator<BigDecimal>
を2つ追加します。BigDecimal
メソッド参照でBigDecimal::add
.
編集後に更新された回答
新しいデータを追加されたので、新しい回答が表示されます。
List<Invoice> invoiceList = new ArrayList<>();
//populate
Function<Invoice, BigDecimal> totalMapper = invoice -> invoice.getUnit_price().multiply(invoice.getQuantity());
BigDecimal result = invoiceList.stream()
.map(totalMapper)
.reduce(BigDecimal.ZERO, BigDecimal::add);
を追加した以外は、ほとんど同じです。
totalMapper
からの関数を持つ
Invoice
から
BigDecimal
で、その請求書の合計金額を返します。
次に
Stream<Invoice>
にマップし、それを
Stream<BigDecimal>
にリダクションし、さらに
BigDecimal
.
さて、OOP設計の観点から、私は実際に使用することをお勧めします。
total()
メソッドを定義しておくと、さらに簡単です。
List<Invoice> invoiceList = new ArrayList<>();
//populate
BigDecimal result = invoiceList.stream()
.map(Invoice::total)
.reduce(BigDecimal.ZERO, BigDecimal::add);
ここでは、メソッドの参照を直接
map
メソッドを使用します。
関連
-
javaで非静的な解を静的な参照にすることができない
-
eclipseにプロジェクトをインポートした後、Editorにmain typeが含まれない問題
-
ブラウザでの大容量ファイルスライスアップロード(Javaサーバサイド実装)
-
[解決済み] Mavenを使用して、依存関係を持つ実行可能なJARを作成するにはどうすればよいですか?
-
[解決済み] ランダムな文字列を使用するこのコードは、なぜ "hello world" と表示されるのですか?
-
[解決済み] Java 8 JDK を使用して、Iterable を Stream に変換する
-
[解決済み] javaストリームで整数のリストを合計する方法は?
-
[解決済み】JSP 2を使用して、JSPファイル内のJavaコードを回避するにはどうすればよいですか?
-
[解決済み】ストリームを使った地図作成で重複を無視する。
-
[解決済み】ストリームを使用して、オブジェクトのリストをtoStringメソッドから取得した文字列に変換する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
スタイルが読み込まれず、ブラウザコンソールでエラーが報告される。リソースはスタイルシートとして解釈されますが、MIMEタイプtext/htmlで転送されます。
-
java の例外が発生しました java
-
スキャナは、タイプに解決することはできません最もルーキー初心者の質問
-
eclipse の実行時に java 仮想マシンが見つからなかった
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException: 1
-
linux run jarfile Invalid or corrupt jarfile error.
-
Exception: java.util.NoSuchElementException: 行が見つかりません
-
このラインで複数のマーカーを解決する方法
-
ローカルリソースのロードが許可されていない場合の解決策
-
Maven Pluginの実行がライフサイクル設定の対象外であるエラーの解決