お疲れ様です。はるさらと申します。
Javaで数値計算を扱う際に便利なクラスとしてBigDecimalがあります。
精度の高い計算が可能な一方で、「0除算」に関しては注意が必要です。
この記事では、経験の浅い方にも分かりやすいように、
BigDecimalでの0除算の挙動や対策方法を具体例を交えて解説します。
BigDecimalでの0除算はどうなるのか?
結論から言うと、BigDecimalで0除算を行うと ArithmeticException が発生します。
intやdoubleと異なり、BigDecimalは例外を投げる仕様です。
これは安全に数値計算を行うための仕組みですが、
経験の浅い方にとっては意外な落とし穴になることがあります。
Javaの他の型との違いを確認する
まずは、BigDecimal以外の型で0除算を行った場合の挙動を比較してみましょう。
public class DivisionSample {
public static void main(String[] args) {
// int型の0除算
try {
int result1 = 10 / 0; // ArithmeticException
} catch (Exception e) {
System.out.println("int: " + e);
}
// double型の0除算
double result2 = 10.0 / 0.0; // Infinity
System.out.println("double: " + result2);
// BigDecimal型の0除算
try {
BigDecimal a = new BigDecimal("10");
BigDecimal b = BigDecimal.ZERO;
BigDecimal result3 = a.divide(b); // ArithmeticException
} catch (Exception e) {
System.out.println("BigDecimal: " + e);
}
}
}
実行結果は以下の通りです。
int: java.lang.ArithmeticException: / by zero
double: Infinity
BigDecimal: java.lang.ArithmeticException: Division by zero
doubleの場合はInfinityになりますが、
BigDecimalでは例外が発生します。
この点を理解しておかないと、思わぬバグにつながります。
BigDecimal.divideでエラーになるケースと対策
基本的な例外処理の書き方
BigDecimalを使う際には、0除算を明示的にチェックするのが基本です。
BigDecimal numerator = new BigDecimal("100");
BigDecimal denominator = BigDecimal.ZERO;
if (denominator.compareTo(BigDecimal.ZERO) == 0) {
System.out.println("0除算はできません");
} else {
BigDecimal result = numerator.divide(denominator);
System.out.println(result);
}
compareTo(BigDecimal.ZERO)を使うと、
分母が0かどうかを判定できます。
実務でよく使う「割り算+丸め」のサンプル
実務では、0ではない分母でも「割り切れないケース」が多々あります。
そのため、divideには丸めモードを指定することが一般的です。
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
// 割り算+スケール(小数点桁数)+丸めモードを指定
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
System.out.println(result); // 3.33
丸めモードを指定することで、ArithmeticException: Non-terminating decimal expansion を回避できます。
代替手法の比較
① 例外処理で対応する方法
BigDecimal numerator = new BigDecimal("10");
BigDecimal denominator = BigDecimal.ZERO;
try {
BigDecimal result = numerator.divide(denominator);
System.out.println("結果: " + result);
} catch (ArithmeticException e) {
System.out.println("分母が0なので処理できません");
}
→ 例外処理を利用するパターン。
シンプルですが例外を多用すると可読性が落ちます。
② 事前チェックで対応する方法
if (denominator.compareTo(BigDecimal.ZERO) != 0) {
BigDecimal result = numerator.divide(denominator, 2, RoundingMode.HALF_UP);
}
→ 実務ではこちらの方が好まれます。無駄に例外を発生させないため、
パフォーマンスやログのノイズが減ります。
③ Optionalを使ったラップ
Java8以降ならOptionalを使って、0除算を安全にラップできます。
public static Optional<BigDecimal> safeDivide(BigDecimal num, BigDecimal den) {
if (den.compareTo(BigDecimal.ZERO) == 0) {
return Optional.empty();
}
return Optional.of(num.divide(den, 2, RoundingMode.HALF_UP));
}
// 利用側
safeDivide(new BigDecimal("10"), BigDecimal.ZERO)
.ifPresentOrElse(
v -> System.out.println("結果: " + v),
() -> System.out.println("分母が0でした")
);
→ 事前チェックを関数化することで、コードの再利用性が高まります。
注意点:経験の浅い方が間違えやすいポイント
equalsではなくcompareToを使う
BigDecimalはスケールの違いも区別するため、new BigDecimal("0.0").equals(BigDecimal.ZERO)はfalseになります。
→compareTo(BigDecimal.ZERO) == 0を使うこと。- 丸めモードを指定しないと例外が発生する
1 / 3のような割り算では、丸め指定がないとArithmeticExceptionになります。 - doubleとの違いを理解する
doubleならInfinityになりますが、BigDecimalでは必ず例外です。
関連記事の紹介
今回のテーマと関連のある記事も参考にしてみてください。
- 【Java】0除算の挙動と対策を徹底解説|初心者向けサンプル付き
https://harusara22.work/java-division-by-0/ - 【Java】0埋めで文字列や数値を整形する方法まとめ【初心者向けサンプル付き】
https://harusara22.work/zero-padding/ - 【Java】String.formatで0埋めする方法まとめ|初心者向けサンプル付き解説
https://harusara22.work/javastring-format-zero-padding/
まとめ
- BigDecimalで0除算を行うと必ず
ArithmeticExceptionが発生する - 事前に
compareTo(BigDecimal.ZERO)でチェックするのが安全 - 割り算の際には丸めモードを指定することが必須
- 実務では事前チェック+丸めモードの組み合わせが基本
BigDecimalは金融システムなどで必須のクラスですが、
挙動を正しく理解していないと大きなバグの原因になります。
今回のサンプルを参考に、安全に利用してみてください。
どなたかのお役に立てば幸いです。
それではまたー!





































