概要

消費税計算は金額を扱うシステムで必ず必要になる処理ですが、端数処理の方式(四捨五入、切り捨て、切り上げ)によって1円の差が生まれます。double や float では誤差が避けられないため、業務用途では BigDecimal を使うのが鉄則です。税抜から税込への変換、税込から税抜への逆算、軽減税率(8%)と標準税率(10%)の使い分けを BigDecimal で実装した。RoundingMode の選び方と、明細と合計で端数処理のタイミングが異なる場合の対応も整理している。

使いどころ

請求書の明細行ごとに消費税を計算し、合計金額と突き合わせる

POS レジで税込表示価格から税抜金額を逆算する

軽減税率対象商品と標準税率商品を混在して合計する

コード例

消費税計算ユーティリティ
import java.math.BigDecimal;
import java.math.RoundingMode;

public class TaxCalculator {

    private static final BigDecimal STANDARD_RATE =
        new BigDecimal("0.10");
    private static final BigDecimal REDUCED_RATE =
        new BigDecimal("0.08");

    public static BigDecimal withTax(
            BigDecimal price, BigDecimal rate,
            RoundingMode mode) {
        var tax = price.multiply(rate)
            .setScale(0, mode);
        return price.add(tax);
    }

    public static BigDecimal withoutTax(
            BigDecimal priceWithTax, BigDecimal rate,
            RoundingMode mode) {
        return priceWithTax.divide(
            BigDecimal.ONE.add(rate), 0, mode);
    }

    public static void main(String[] args) {
        var price = new BigDecimal("1980");
        System.out.println("税抜: " + price);
        System.out.println("税込(10%): " +
            withTax(price, STANDARD_RATE,
                RoundingMode.FLOOR));
        System.out.println("税込(8%): " +
            withTax(price, REDUCED_RATE,
                RoundingMode.FLOOR));
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

switch 式で商品種別による税率の切り替えが簡潔になる。record で金額と税額をまとめると可読性が上がる。

Java 17
// Java 17: switch 式で税率を切り替え
String itemType = "food";
BigDecimal rate = switch (itemType) {
    case "food", "newspaper" -> REDUCED_RATE;
    default -> STANDARD_RATE;
};
BigDecimal total = calcTaxIncluded(price, rate);

Library Comparison

標準 API(BigDecimal + RoundingMode)消費税計算の端数処理を自分で制御したいとき。依存ゼロで動作し、端数処理方式を明示的に指定できる。通貨コードや為替の概念は自前で管理する必要がある。
JSR 354 (Money API)通貨型を厳密に扱いたい場合。多通貨対応が必要な場面。標準化されたが JDK に同梱されていないため外部依存が増える。国内の消費税計算だけなら過剰。
Apache Commons Math高精度の数値演算や統計計算が併せて必要な場合。消費税計算だけなら BigDecimal で十分。依存に見合うかはプロジェクト規模による。

注意点

BigDecimal の生成には new BigDecimal('0.1') のように文字列を使うこと。double リテラルは誤差が入る。

端数処理のタイミング(明細ごとか合計か)は取引先との合意に依存する。

税率は法改正で変わる可能性があるため、定数管理を推奨する。

現場では「請求書の合計が明細の税込小計の合算とずれる」という問題が頻発する。明細ごとに切り捨てか、合計に対して一括で端数処理するかを設計段階で決め、テストデータに端数が出るケースを含めておくこと。

FAQ

なぜ double ではなく BigDecimal を使うのですか?

double は2進浮動小数点のため、0.1 を正確に表現できず、金額計算で1円の誤差が生じます。

切り捨てと四捨五入はどちらが一般的ですか?

日本の商慣習では切り捨て(FLOOR/DOWN)が多いですが、契約や業種で異なるため要確認です。

軽減税率と標準税率を混在させるときの注意点は?

明細行ごとに税率を判定し、税率別に小計を出してから合算する方法が安全です。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます