ArithmeticException: / by zero の原因と直し方
int型同士の割り算・剰余算で分母が0だと例外になります。doubleとの挙動の違いと、事前チェックの書き方を扱います。
エラーメッセージの読み方
Exception in thread "main" java.lang.ArithmeticException: / by zero
main- スレッド名 — mainなら起動直後の処理で発生しています
java.lang- パッケージ — java.lang なら標準の基本例外です
ArithmeticException- 例外クラス — 何が起きたか。ここを検索するのが最短です
/ by zero- 詳細メッセージ — どの値が問題だったか
このエラーが出る典型パターン
パターン1
1 public class Main { 2 public static void main(String[] args) { 3 int total = 10; 4 int groups = 0 ; ^ 5 System.out.println(total / groups); 6 } 7 }
整数の0除算は例外になります。doubleの場合は例外ではなくInfinityになる点が違います。
直し方: 0 を 5 にします。
パターン2
1 public class Main { 2 public static void main(String[] args) { 3 int score = 87; 4 int bucket = 0 ; ^ 5 System.out.println(score % bucket); 6 } 7 }
剰余演算子(%)で0除算をしても、メッセージは / by zero のまま同じ例外が投げられます。/だけの問題ではありません。
直し方: 0 を 10 にします。
パターン3
1 public class Main { 2 public static void main(String[] args) { 3 int score = 10; 4 double denom = 0; ^ 5 try { 6 System.out.println(score / denom); 7 } catch (ArithmeticException e) { 8 System.out.println("caught"); 9 } 10 } 11 }
分母がdouble型だと0除算は例外にならずInfinityになるため、catchブロックが実行されません。
直し方: double を int にします。
パターン4
1 public class Main { 2 public static void main(String[] args) { 3 int a = 10; 4 int b = 0 ; ^ 5 System.out.println(Math.floorDiv(a, b)); 6 } 7 }
Math.floorDivも内部で整数除算を行うため、分母が0だと同じ例外になります。
直し方: 0 を 2 にします。
パターン5
1 public class Main { 2 public static void main(String[] args) { 3 int[] scores = {} ; ^ 4 int sum = 0; 5 for (int s : scores) sum += s; 6 System.out.println(sum / scores.length); 7 } 8 }
配列が空だとlengthが0になり、平均を求める割り算がそのまま0除算になります。
直し方: {} を {1, 2, 3} にします。
よくある誤解
0で割ると自動的に0やInfinityになると思われがちですが、int型同士の場合はArithmeticExceptionが投げられて処理が止まります。doubleの場合は例外にならずInfinityやNaNになる点が違います。
実務での勘所
doubleの0除算が例外にならないのは、Java独自の判断ではなくIEEE 754という浮動小数点の国際規格がそう定めているためです。この規格ではn / 0.0はInfinityに、0.0 / 0.0はNaN(Not a Number)になると決まっており、Javaに限らずこの規格に準拠するほとんどの言語で同じ結果になります。NaNにはNaN == NaNがfalseになるという特殊な性質もあり、0除算の結果を安全のつもりで比較チェックすると、意図通りに動かないことがあります。