Java | Java 標準ライブラリ:BigDecimal の加算減算

Java Java
スポンサーリンク

なぜ BigDecimal の「加算・減算」が特別なのか(全体像)

BigDecimal は「お金など誤差が許されない小数」を扱うためのクラスでしたね。
その代わり、+- の演算子は使えません。

+- の代わりに

  • 加算 → add
  • 減算 → subtract

というメソッドを使います。

ここを曖昧なまま書き始めると、

  • + が使えないことにイライラして変な変換をし始める
  • new BigDecimal(double) を混ぜて誤差を持ち込んでしまう
  • null やマイナス値の扱いでバグる

といったことになりがちです。

「どう足す・どう引く」がパターンとして頭に入っていると、金額ロジックを書くのが一気に楽になります。


基本の形:add / subtract でシンプルに足す・引く

まずは素朴な加算から

BigDecimal 同士の加算は add で行います。

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("100.50");
BigDecimal b = new BigDecimal("200.25");

BigDecimal sum = a.add(b);  // 100.50 + 200.25

System.out.println(sum);    // 300.75
Java

ここで重要なのは、

  • ab の中身は変更されない(BigDecimal は不変オブジェクト)
  • 戻り値として「新しい BigDecimal」が返る

という点です。

つまり、「代入し直さないと、元の変数は変わらない」という感覚を持っておく必要があります。

BigDecimal total = BigDecimal.ZERO;

total.add(new BigDecimal("100"));   // total は変わらない!
System.out.println(total);          // 0

total = total.add(new BigDecimal("100"));  // こう書いて初めて 100 になる
System.out.println(total);                 // 100
Java

この「戻り値をちゃんと受け取る」が、BigDecimal を扱ううえでとても重要です。

減算は subtract を使う

減算は subtract で行います。

BigDecimal a = new BigDecimal("300");
BigDecimal b = new BigDecimal("120");

BigDecimal diff = a.subtract(b);  // 300 - 120

System.out.println(diff);         // 180
Java

イメージとしては、

  • a.add(b)a + b
  • a.subtract(b)a - b

と対応しています。


金額の「累計」を足していくパターン(ここはよく使う)

典型的なパターン:for ループで合計を求める

商品の金額を合計する例で考えてみましょう。

BigDecimal[] prices = {
    new BigDecimal("100.50"),
    new BigDecimal("200.25"),
    new BigDecimal("50.25")
};

BigDecimal total = BigDecimal.ZERO;   // 合計は 0 からスタート

for (BigDecimal price : prices) {
    total = total.add(price);         // 戻り値で total を更新
}

System.out.println("合計: " + total); // 351.00
Java

ここでのポイントは、

  • 初期値は BigDecimal.ZERO を使う(new BigDecimal("0") より読みやすく安全)
  • total = total.add(price); のように、「毎回代入し直す」ことを忘れない

という 2 点です。

total.add(price); と書くだけで満足してしまうと、total は変わりません。
初心者がかなりやりがちなバグなので、「BigDecimal は不変。合計は必ず代入し直す」と体に覚えさせてください。


マイナス値・返金・割引などでの減算の考え方

subtract で「引く」か、「マイナスを足す」か

例えば、注文金額から割引額を引きたいとします。

BigDecimal amount = new BigDecimal("1000");     // 注文金額
BigDecimal discount = new BigDecimal("200");    // 割引額

BigDecimal finalAmount = amount.subtract(discount);  // 1000 - 200 = 800

System.out.println(finalAmount);                     // 800
Java

シンプルに subtract を使えば OK です。

一方で、「マイナスの値を add する」という書き方もできます。

BigDecimal amount = new BigDecimal("1000");
BigDecimal discount = new BigDecimal("200");

BigDecimal finalAmount = amount.add(discount.negate()); // discount.negate() は -200

System.out.println(finalAmount);                         // 800
Java

negate() は「符号を反転する」メソッドです。

  • discount が 200 → discount.negate() は -200
  • add(-200) → 実質 subtract になる

subtract を素直に使うか、negate() と組み合わせて add を使うかは好みですが、
「割引や返金を“マイナスの売上”として扱う」ような設計では negate() が出てくることが多いです。


new BigDecimal(…) の罠を、加算・減算でも絶対に避ける

double から new BigDecimal(double) しない(重要)

例えば、こういうコードはやってはいけません。

double price = 0.1;
BigDecimal a = new BigDecimal(price); // NG
BigDecimal total = BigDecimal.ZERO;
total = total.add(a);
Java

pricedouble の時点で、すでに誤差を含んだ値になっています。
その誤差ごと BigDecimal に持ち込んでしまうと、

「BigDecimal を使っているのに、きっちりした計算になっていない」

という本末転倒な状況になります。

BigDecimal はできるだけ最初から文字列で作る
(もしくは、整数部分とスケールを明確に決めてから作る)

というのが鉄則です。

BigDecimal a = new BigDecimal("0.1");  // これなら OK
Java

加算・減算そのものよりも、この「どう作るか」の方がずっと大事だと思ってください。


「null かもしれない BigDecimal を足したい」ときの考え方

null のまま add すると即 NullPointerException

DB から取ってきた値などで、BigDecimalnull のことがあります。

BigDecimal total = null;
total = total.add(new BigDecimal("100"));  // NullPointerException
Java

これもよくある事故です。

合計処理などで「最初は null で、そのうち値が入るかも」という設計は、
BigDecimal とは相性が悪いです。

一番シンプルな対処は、「最初から 0 にしておくこと」です。

BigDecimal total = BigDecimal.ZERO;          // 最初から 0 にしておく
total = total.add(new BigDecimal("100"));    // OK
Java

もしどうしても null が紛れ込む可能性があるなら、
「null を 0 として扱う」というルールをどこかで一度決めてしまうと、
以降の加算ロジックが楽になります。

例えば:

BigDecimal safe(BigDecimal value) {
    return (value != null) ? value : BigDecimal.ZERO;
}

total = safe(total).add(new BigDecimal("100"));
Java

ですが、設計としては「合計は最初から 0 にする」の方がシンプルでおすすめです。


まとめ:BigDecimal の加算・減算で初心者が押さえるべきポイント

BigDecimal の足し算・引き算は、初心者のうちにこう整理しておくと楽になります。

  • + / - は使えない。加算は add、減算は subtract
  • BigDecimal は不変なので、total = total.add(x); のように「戻り値で上書き」する必要がある。
  • 合計の初期値は BigDecimal.ZERO を使うと安全で読みやすい。
  • 割引や返金では subtractnegate() を組み合わせた add を使う設計が多い。
  • new BigDecimal(double) で誤差を持ち込まない。文字列から作るのが基本。
  • 合計を null スタートにしない。0 スタートにするか、null を 0 として扱う場所を1か所に決める。

タイトルとURLをコピーしました