ゼロ除算以外でArithmeticException が起こるのはどのようなときですか?

こんにちは。ゆうせいです。

新人研修中に受講者から以下の質問をいただきました。

ゼロ除算以外でArithmeticException が起こるのはどのようなときですか?

今回はこの質問に答えたいと思います。

こんにちは。ゆうせいです。

JavaのArithmeticExceptionが発生するケースと例外処理の基礎知識

プログラミング言語のJavaを学習していると、計算処理の途中でプログラムが停止してしまうことがあります。その原因の一つがArithmeticException(算術例外)です。この例外は、実行時に計算不可能な数式が呼び出された際に発生します。

一般的にはゼロで数値を割る「ゼロ除算」が有名ですが、それ以外にもこの例外が発生する具体的なケースが存在します。本記事では、初心者の方にも分かりやすく、その発生条件と仕組みを解説します。

ArithmeticExceptionが発生する主なケース

JavaにおいてArithmeticExceptionがスローされるのは、主に「整数」の計算において数学的に定義できない操作が行われたときです。

1. 整数によるゼロ除算

最も代表的な例は、整数を0で割ろうとした場合です。コンピュータにとって、ある数を0で割るという命令は、答えを定義できず処理を継続できない状態を指します。

2. 整数演算によるオーバーフロー(厳密なメソッド使用時)

通常の算術演算子(+, -, *, /)を使用した計算では、計算結果が型の保持できる最大値を超えてもArithmeticExceptionは発生しません。代わりに、数値が一周して最小値に戻る「ラップアラウンド」という現象が起こります。

しかし、Java 8から導入されたMathクラスの厳密な計算メソッド(exactメソッド)を使用すると、数値が型の許容範囲を超えた際にArithmeticExceptionが発生します。

例えば、int型の最大値に1を加算する場合を考えてみましょう。高校数学の集合で例えるなら、3人乗りの小さなボートにムリやり4人目を乗せようとして、ボートが沈没(例外発生)してしまうような状態です。

以下に、具体的に例外が発生するコードの例を示します。

public class Main {
    public static void main(String[] args) {
        int max = Integer.MAX_VALUE;
        // 通常の加算では例外は出ず、負の数に回り込みます
        // Math.addExactを使用すると、許容範囲を超えた瞬間にArithmeticExceptionが発生します
        int result = Math.addExact(max, 1);
    }
}

このMath.addExactメソッドは、予期せぬ計算誤差を防ぎ、正しく計算が完了したことを保証したい場合に非常に有効です。

3. BigDecimalクラスにおける無限小数の扱い

金融計算などで使われるBigDecimalクラスにおいて、割り算の結果が割り切れず、かつ「どの桁で四捨五入するか」を指定しなかった場合にもArithmeticExceptionが発生します。

10を3で割ると3.333...と無限に続きます。Javaのプログラムに対して「最後まで正確に出して」と命令しても、メモリには限りがあるため、終わりが見えない計算を命じられたプログラムは「処理不能」として例外を投げます。

サンプルコード

以下のコードを実行すると、実行時にArithmeticExceptionが発生します。

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("10");
        BigDecimal num2 = new BigDecimal("3");

        // 10 ÷ 3 を計算しますが、丸め処理の指定がないため例外が発生します
        BigDecimal result = num1.divide(num2);
        
        System.out.println(result);
    }
}

例外を回避するための修正方法

この問題を解決するには、計算結果をどの程度の精度で収めるかを指示する「スケール(小数点以下の桁数)」と「丸めモード(四捨五入や切り捨てなど)」を指定する必要があります。

修正後のコード

以下の例では、小数点第3位までを計算し、それ以降を四捨五入するように指定しています。

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Main {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("10");
        BigDecimal num2 = new BigDecimal("3");

        // 小数点第3位まで求め、第4位を四捨五入する指定
        BigDecimal result = num1.divide(num2, 3, RoundingMode.HALF_UP);
        
        System.out.println(result); // 出力結果: 3.333
    }
}

ArithmeticExceptionのメリットとデメリット

この例外が存在することには、開発上の明確な理由があります。

メリット

計算結果が不正確なまま処理が進行することを防げる点です。銀行のシステムなどで、最大値を超えた数値が誤ってマイナスとして処理されると甚大な被害が出ます。例外が発生することで、誤ったデータが保存される前にプログラムを安全に停止、あるいは修正へと導くことができます。

デメリット

適切に例外処理(try-catch構文など)を記述していない場合、アプリケーション全体が強制終了してしまう点です。利用者の操作中に突然画面が消えるような事態を招くため、発生が予想される箇所にはあらかじめ対策を講じる必要があります。

算術例外を理解するための学習ステップ

ArithmeticExceptionをマスターし、堅牢なプログラムを作成するためには、以下のステップで学習を進めることを推奨します。

  1. 整数と浮動小数点数の違いを理解するJavaでは、浮動小数点数(double型など)で0除算を行っても例外は発生せず、Infinity(無限大)という値が返されます。まずは型による挙動の違いを確認してください。
  2. Mathクラスのexactメソッドを試す数値の安全性を高めるために、どのようなメソッドが用意されているか公式ドキュメントを参照してください。
  3. 例外処理(try-catch)の記述方法を学ぶ例外が発生した際に、プログラムを止めずに「エラーメッセージを表示して次の処理へ進む」といった制御の流れを習得してください。

これらのステップを順に踏むことで、計算ミスによる不具合の少ない、高品質なコードを書く力が身につきます。

グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。