JavaのArithmeticExceptionとは?原因・対処法・ゼロ除算の落とし穴を初心者向けに解説

Java入門・実践
スポンサーリンク

ゼロ除算との衝突は、ある日突然やってくる──

「Arithmetic?アリスマジック?なにそれ魔法?」

Javaでエラーに出会ったばかりの頃、そんな風に思ったのを今でも覚えています。

しかも出てきた例外名は ArithmeticException。

英語の響きからして難しそうだし、Exceptionってだけでちょっとビビる。

でも、よくよく見てみると──

Java
int result = 10 / 0; // ← こ れ か  

そう。ただ割り算しただけなんです。ゼロで。

割り算って、なんとなく “割れなかったら0になるのかな〜” くらいの感覚で書いていた自分に、 Javaは静かに、でも確実に教えてくれました。

「その計算、ムリです」と。

本記事では、この ArithmeticException にまつわる原因や対処法、 そして”ゼロで割ったらなぜいけないのか”という素朴な疑問にもお答えしていきます。

初心者の方にもできるだけやさしく、つまづきながらでも前に進めるように、 一緒にこの“算術の落とし穴”をのぞいてみましょう!

スポンサーリンク
  1. はじめに
  2. ArithmeticExceptionとは?
    1. 名前からしてむずかしそうなんですが…
    2. どんなときに発生するの?
    3. RuntimeExceptionの仲間です
    4. え、割っても落ちないパターンもあるの?
    5. この章のまとめ
  3. ゼロ除算の落とし穴
    1. ただ割っただけなのに…?
    2. 数学的には「未定義」の世界
    3. Javaが落ちるのは“整数”のときだけ?
      1. int などの整数型
      2. double などの浮動小数点型
    4. じゃあ、double で書けば安全?
    5. ゼロ除算を防ぐための第一歩
    6. この章のまとめ
  4. よくあるやらかし例とデバッグのポイント
    1. ケース①:ユーザー入力をそのまま使って割る
      1. よくあるパターン
      2. 対処法
    2. ケース②:配列の要素から動的に割ってしまう
      1. よくあるパターン
      2. 対処法
    3. ケース③:計算結果を割り算に使ってしまう
      1. うっかりポイント
      2. 対処法
    4. ケース④:割る相手を関数から返すようにしている
      1. よくある盲点
      2. 対処法
    5. デバッグ時のチェックポイント
    6. この章のまとめ
  5. どう防ぐ?
    1. ゼロを恨むより、ゼロと付き合う設計を
    2. 対策①:割る前にゼロかどうかを確認する
    3. 対策②:try-catch で例外をキャッチして落ちないコードに
    4. 対策③:分母がゼロになる“流れ”を設計で潰す
    5. 対策④:入力チェック+共通ユーティリティ化
    6. この章のまとめ
  6. 設計で減らす
    1. 割れる前提で書いていたのは、誰?
    2. 割れる/割れないを“型”で表現する
    3. 設計を通して“期待値”を共有する
    4. 設計を変えるヒント集
    5. 「割れる前提」から「割れない設計」へ
    6. この章のまとめ
  7. まとめ
    1. 落ちた理由が、学びになった
    2. 書けるようになるより、“気づけるようになる”こと
    3. 設計の中にも、思いやりはある
    4. 最後に

はじめに

――ゼロで割ったら落ちた

「Arithmeticって、何ですか?」 Javaのエラーメッセージに初めてその単語が出てきたとき、私は本気でそう思っていました。

Java
int result = 43 / 0;

この1行。 ただ、ゼロで割ったというだけなんです。

でもプログラムは、そこで落ちました。

しかも出てきたのは

Exception in thread "main" java.lang.ArithmeticException: / by zero

……えっ、割っただけですけど? ゼロってダメなんですか?

今なら「整数の割り算でゼロ除算したら落ちるよ」というルールを知っています。

でも当時の私は、“何が悪いのかすら分からない”という状態でした。

  • 「割れなかったら0になるのかな?」
  • 「エラーっていうほど深刻なこと?」
  • 「ていうかArithmeticって何語?」(←英語です)

そんなふうに、まったくピンとこないままスタックトレースを眺めていたのをよく覚えています。

この ArithmeticException というエラーは、初心者がほぼ一度は遭遇する“はじめての落とし穴”のひとつです。 一見シンプルなゼロ除算に見えて、

  • どうしてエラーになるのか?
  • どんなときに起きやすいのか?
  • どうやって防げばいいのか?

という、プログラミングの考え方をじっくり学べるチャンスでもあります。

この記事では、そんな ArithmeticException を出発点にして

  • ゼロ除算の原因と原理
  • よくあるやらかし例とデバッグのコツ
  • “落ちないコード”を目指す設計の視点

までを、初心者の私と同じように悩んできた人に寄り添ってお届けします。

“知らなかった自分”にも、“つまずいた誰か”にも届くと嬉しいです。

では、一緒にこの算術の世界をのぞいてみましょう!

ArithmeticExceptionとは?

――実行時に起きる“算術の罠”

名前からしてむずかしそうなんですが…

ArithmeticException 正直この名前、初心者の頃の私にはいかにも「難解な例外です感」を放っていました。

でも、じつはこれ、算術演算(=arithmetic)にまつわる実行時エラーのことなんです。

難しく言ってるけど、起きていることはシンプル。

割っちゃいけないものを割ったり、やっちゃいけない計算をしたとき に、Javaが「それは無理だよ」と教えてくれる、そんな例外です。

どんなときに発生するの?

最もよくあるのは、整数型(int や long)でのゼロ除算です。

Java
int x = 10;
int y = 0;
int result = x / y; // ❌ ArithmeticExceptionが発生

Javaはこうした場合、コンパイルは通してくれます。

でも、実行すると…

Exception in thread "main" java.lang.ArithmeticException: / by zero

しっかり怒られます。

なぜ怒られるのかというと、整数の世界では「ゼロで割る」という操作は“定義されていない”からです(数学的にも未定義なんですよね)。

RuntimeExceptionの仲間です

ArithmeticException は RuntimeException のサブクラス。

つまり、

  • 実行時に初めて発生する(=コンパイルエラーにはならない)
  • try-catch で捕まえなくても書けてしまう(=油断しやすい)

という性質を持っています。

これ、初心者が「え、普通に動くと思ってたのに…」と混乱しやすいポイントでもあります。

え、割っても落ちないパターンもあるの?

実は int 型などの整数ではゼロ除算でエラーになりますが、 float や double の浮動小数点型では、なんと落ちません。

Java
double result = 10.0 / 0.0;
System.out.println(result); // Infinity が出力される

びっくりですよね。 Javaでは浮動小数点のゼロ除算はIEEE 754規格に基づいて“無限大”として扱うため、エラーにはなりません。

こういった挙動の違いも、ArithmeticException を正しく理解するうえで大切なポイントです。

この章のまとめ

観点要点
発生タイミング実行時(=RuntimeException)
よくある原因整数型でのゼロ除算
挙動の違いint / 0 → 落ちる / double / 0.0 → Infinity
エラーメッセージ ArithmeticException: / by zero

次の章では、「分母ゼロで爆発してしまうコードって、どんな場面でありがち?」という “あるあるやらかしパターン” を実例ベースでご紹介します!

ゼロ除算の落とし穴

――なぜ0で割っちゃダメなの?

ただ割っただけなのに…?

プログラムを書いていて、ついこんなコードを書いてしまったことはありませんか?

Java
int a = 100;
int b = 0;
int result = a / b; // ❌ ArithmeticException: / by zero

「普通に計算しただけなんだけど…」

「数学的に“ゼロでは割れない”って知ってはいたけど、プログラムでもそんなに厳しいの?」 そう感じた私のような初心者はきっと多いはずです。

でも実は、ゼロ除算は“計算できない”ではなく“定義できない”操作。

そこにはJavaが落ちる、しっかりとした理由がありました。

数学的には「未定義」の世界

学校の数学でも習ったかもしれませんが、「ゼロで割ること」は定義されていません。

  • 10 ÷ 2 = 5 → OK(2×5=10と戻れる)
  • 10 ÷ 0 = ? → ❌(0×?=10を満たす数字が存在しない)

つまり、「割った結果」を定義しようとしても、どんな数をかけても戻せない。 このような計算は、そもそも成り立っていないのです。

Javaが落ちるのは“整数”のときだけ?

実は、整数型と浮動小数点型(float, double)では、ゼロ除算の挙動が違います。

int などの整数型

Java
int result = 10 / 0; // → ArithmeticException!

→ 落ちます。実行時に例外がスローされます。

double などの浮動小数点型

Java
double result = 10.0 / 0.0;
System.out.println(result); // → Infinity(エラーにはならない)

→ 落ちません。 結果として Infinity が返ってきます(ゼロ除算ではなく「無限大」として扱われます)。

これは IEEE 754 という浮動小数点の規格に基づく仕様であり、 浮動小数点の場合は例外ではなく特別な数値(Infinity, NaN)として処理されるんです。

じゃあ、double で書けば安全?

残念ながらそういう話ではありません…!

double ではゼロ除算で例外が発生しないぶん、Infinity や NaN を気づかずに使い続けてしまうリスクがあります。

Java
double x = 0.0;
double result = 100.0 / x; // → Infinity

System.out.println(result * 0); // → NaN(Not a Number)

気づかぬうちに「数字っぽい何か」が伝播して、想定外の計算結果になることも。

つまり、「落ちない ≠ 安全」というわけです。

ゼロ除算を防ぐための第一歩

ArithmeticException は、ある意味とてもまじめな失敗です。

プログラムは「ゼロで割るのは数学的にアウト」と理解し、ちゃんと止まってくれます。

このエラーに出会ったことで私が学んだのは

  • 割るときは「分母がゼロになるかもしれない」前提で考えること
  • 「ゼロになることなんてないでしょ」は通用しないこと

これが後に「値の前提条件を明示する」という設計の基本姿勢にもつながっていきました。

この章のまとめ

ポイント内容
ゼロ除算とは?数学的に“定義されない”操作(割れない)
Javaの対応int / 0 → 例外/double / 0.0 → Infinity
落ちないのは安全?いいえ。InfinityやNaNが静かにバグを呼ぶ場合もあり
学びの視点「計算できるはず」という思い込みを捨てて前提条件を明示しよう

次の章では、どんな場面で実際にArithmeticExceptionが起きやすいのか? という、現場あるあるの“やらかし例”とそのデバッグのコツを見ていきます!

よくあるやらかし例とデバッグのポイント

――そのゼロ、どこから来たの?

ケース①:ユーザー入力をそのまま使って割る

Java
Scanner sc = new Scanner(System.in);
System.out.print("割る数(分母)を入力してください: ");
int denominator = sc.nextInt();

int result = 100 / denominator; // ❌ ゼロが入れば即クラッシュ

よくあるパターン

  • 「使う人がちゃんと入力してくれるはず」と信じたまま、値チェックせずに割る
  • テストでは落ちなかったのに、本番ユーザーの“うっかり0入力”でクラッシュ

対処法

  • ユーザーの入力値は 信頼しないのが基本姿勢
  • 事前に if (denominator != 0) でチェック or エラーメッセージを出す

ケース②:配列の要素から動的に割ってしまう

Java
int[] data = {10, 20, 0, 40};

for (int i = 0; i < data.length; i++) {
    int result = 100 / data[i]; // ❌ index=2 で爆発!
    System.out.println(result);
}

よくあるパターン

  • データセットの中に“ゼロが混じっていた”ことに気づかない
  • CSVやDBなど外部データ由来の配列で起きやすい

対処法

  • data[i] != 0 をループ内でチェック
  • または、“ゼロの可能性があるデータセット”として事前にバリデーションをかける

ケース③:計算結果を割り算に使ってしまう

Java
int x = 10 - 10; // 結果は0
int result = 50 / x; // ❌ 気づきにくいゼロ除算

うっかりポイント

  • 変数名が意味を持っていると、ゼロになるとは思わずに使ってしまう
  • 特に total, count, diff などの変数がゼロになりやすい

対処法

  • “演算結果がゼロになる可能性”を常に意識する
  • 複雑な式は一旦別変数に代入して、中間値をデバッグしやすくする

ケース④:割る相手を関数から返すようにしている

Java
int denominator = calculateSomething(); // 中身は不明…
int result = 123 / denominator; // ❌ 処理の流れによってはゼロになるかも

よくある盲点

  • 関数の戻り値に絶対の信頼を置いてしまう
  • 複数パターンの戻り値がある設計なのに、割り算する側はその前提を持っていない

対処法

  • 関数が「0を返す可能性がある」かどうかを設計上明示する
  • 明示的なチェックと例外処理を含めることで、予期しないゼロ除算を防げる

デバッグ時のチェックポイント

観点チェックすること
分母の値ゼロになりうる経路を洗い出す
関数や入力の戻り値0 が返る条件が存在しないか確認
スタックトレースArithmeticException: / by zero の行番号を見る
実行前のログ出力System.out.println(“分母: ” + denominator); などで手動チェック

この章のまとめ

  • ArithmeticException は「意図してないゼロ」から突然やってくる
  • 入力、配列、演算、関数の戻り値――ゼロの侵入口は意外と多い!
  • バリデーションや事前チェックは “不信” から始まる思いやり
  • “割る前に、ちょっとだけ相手を信じすぎてないか?”を振り返ろう

次章では、こうしたやらかしを“未然に防ぐ書き方”へシフトするための考え方と具体的なコードパターンをご紹介します。

キャッチ&予防の両立、一緒に目指していきましょう!

どう防ぐ?

――ArithmeticException対策の基本

ゼロを恨むより、ゼロと付き合う設計を

ArithmeticException が起きたとき、つい「なんでゼロなんか入ってきたの…」と文句を言いたくなるのですが、本当はゼロが悪いわけではありません。

「ゼロが入るかもしれない」前提でコードを書かなかった私の甘さがあったのだと、あとから気づきました。

では、どうすればゼロ除算を防げるのか?

この章ではその基本パターンと考え方をご紹介します。

対策①:割る前にゼロかどうかを確認する

最もシンプルかつ効果的な方法は、割る直前にゼロチェックを入れることです。

Java
if (denominator != 0) {
    int result = 100 / denominator;
    System.out.println("計算結果:" + result);
} else {
    System.out.println("分母がゼロなので割れません。");
}

ポイント:

  • != 0 の条件を入れるだけで、例外が回避できます
  • エラーメッセージも添えると、ユーザーにとっても親切

応用例

  • 数値を返す代わりに OptionalInt で「割れなかったこと」を明示する設計もアリ

対策②:try-catch で例外をキャッチして落ちないコードに

事前チェックが難しいときは、割り算をtry-catchブロックで囲う方法も有効です。

Java
try {
    int result = 100 / denominator;
    System.out.println("結果:" + result);
} catch (ArithmeticException e) {
    System.out.println("0では割れませんでした!");
}

この書き方は、

  • 複雑な計算フローの中で「どこかでゼロになるかも」というケースに対応できます
  • ただし、常にcatchに頼るのは避けたい(設計が雑になりやすいため)

対策③:分母がゼロになる“流れ”を設計で潰す

例えば分母が他の値の計算結果になっている場合、そもそもゼロになり得ないような値の受け渡し構造を考えることも大切です。

例:関数が0を返す可能性を制御する

Java
public int getValidDenominator() {
    int value = getSomething();
    return (value != 0) ? value : 1; // デフォルト値を返すなどの工夫
}

設計の工夫

  • 「割られる側」だけでなく、「割る側」もゼロを返さない責任をもつ
  • 例外が起きるまで放っておくのではなく、「そもそも起こらないように設計する」視点が重要です

対策④:入力チェック+共通ユーティリティ化

ゼロチェックの条件文を毎回書くのが面倒なときは、共通ユーティリティクラスに切り出して再利用するとスマートです。

Java
public class SafeMath {
    public static OptionalInt safeDivide(int numerator, int denominator) {
        return (denominator == 0) ? OptionalInt.empty() : OptionalInt.of(numerator / denominator);
    }
}

呼び出し側:

Java
OptionalInt result = SafeMath.safeDivide(100, userInput);
result.ifPresentOrElse(
    val -> System.out.println("結果:" + val),
    () -> System.out.println("ゼロでは割れませんでした")
);

この方法のメリット

  • 予防処理を標準化できる
  • 呼び出し側が例外を意識せず、“安全な世界”から始められる

この章のまとめ

やらかし → 対策学び
分母が0かも → != 0 でチェック危険な操作を前提にしない
何か落ちた! → try-catchで拾うユーザーにやさしいエラー処理
毎回if文だるい → 共通化しようコードの可読性&再利用性アップ
設計で防げたかも? → 責任の所在を考える “起きない設計”を意識しよう

次章では、このような対策を通じて得られる設計の視点・気づきにフォーカスして、 “ゼロ除算が教えてくれたこと”を振り返っていきます!

設計で減らす

――「割れること」が前提の設計をやめよう

割れる前提で書いていたのは、誰?

ArithmeticException を繰り返す中で、あるときふと気づきました。

「私は毎回、“分母は割れるもの”として扱ってるな」と。

たしかに現実では「普通に割れる数字しか来ない」というケースもあるかもしれません。

でも、プログラムの世界では“普通”を信じてはいけない。

それは 「割れるかもしれない」ではなく「割れないかもしれない」 を前提にした設計が求められるということなのです。

割れる/割れないを“型”で表現する

たとえば、ゼロになる可能性がある int を渡してくるような関数がある場合、 割り算する側から見ると「こいつ、本当に割って大丈夫なのか?」という疑念が残ります。

よくある設計

Java
public int getCount() {
    return 0; // 条件によってはゼロを返す
}

意図を明示する設計

Java
public OptionalInt getDivisor() {
    int result = calculateSomething();
    return (result != 0) ? OptionalInt.of(result) : OptionalInt.empty();
}

→ 呼び出し側は「割れるかどうか」をコード上で判断でき、例外を未然に防げます。

設計を通して“期待値”を共有する

ゼロを許容するか否か。 例外で止めるか、スキップするか、再計算するか。

こういった分岐をすべて呼び出し側の判断に任せると、コードの読み手が苦しむことになります。

だからこそ設計者側としては:

  • “0を許す関数ですよ”と示す設計
  • “0ではないと保証します”と約束する設計

そのどちらかを選び、割る側に余計な想像をさせないことがやさしさでもあり、強さでもあるのです。

設計を変えるヒント集

よくある書き方替えられる設計のヒント
int result = a / b; OptionalInt safeDivide(int a, int b) を作る
public int getSomething()OptionalInt または Optional<Double> を返す
値だけを渡す関数「割れることが前提の引数かどうか?」をJavadoc or 型で示す

「割れる前提」から「割れない設計」へ

少しずつ、コードの見方が変わってきました。

  • 「今これ、ゼロになるかも?」と考える癖がついた
  • 「この関数、責任持って値くれてる?」と設計から問い直すようになった
  • 「割るって、意外と重い処理なのかもしれない」と思えるようになった

ArithmeticExceptionは、ただの例外というより“設計の甘さを浮き彫りにするレントゲン”だったのかもしれません。

この章のまとめ

気づき設計アクション
割れる前提で書いていた “割れないかも”を前提に変更する
値にゼロが混じっていた Optionalなどで明示的に表現する
呼び出し元に丸投げしていた引数・戻り値に期待値を設計として刻む

次はいよいよ最終章。 このArithmeticExceptionとの出会いから学んだこと、そして“エラーとの付き合い方”について振り返っていきましょう。

まとめ

――ArithmeticExceptionが教えてくれたこと

落ちた理由が、学びになった

Javaを学び始めたころ、ArithmeticException に出会った瞬間は、まるで「え、なに今の…」と戸惑うだけでした。

割り算しただけでエラー?なんでゼロで割っちゃいけないの? 英語もよくわからないし、スタックトレースも怖い。

でも、振り返ってみると、この例外はとてもシンプルで、実は親切なエラーだったのかもしれません。

「その値、本当に割っていいの?」

静かだけど確実なその問いかけは、私に“当たり前と思っていたことを一度立ち止まって考える”という姿勢を教えてくれました。

書けるようになるより、“気づけるようになる”こと

この ArithmeticException をきっかけに、コードを書くときに自然と考えるようになったことがあります。

  • この変数、ゼロになったらまずくない?
  • 計算って本当に「無条件に成功する」操作なんだっけ?
  • ユーザーの入力、本当に信用して大丈夫?

どれも地味な問いかけですが、コードと丁寧に対話するようになる小さな一歩でした。

それってある意味、例外が教えてくれる“優しさ”なのかもしれません。

設計の中にも、思いやりはある

キャストのときも、数値の計算のときも、エラーの種類こそ違えど、共通して大切なのは「想定外を想定に入れる力」。

  • ゼロかもしれない
  • 空っぽかもしれない
  • 来ると思ったものが来ないかもしれない

それらを“ミス”や“バグ”と見るのではなく、最初から想像して設計しておくことで、コードはもっと強く、読みやすく、そしてやさしくなります。

最後に

ArithmeticException は、ただの計算エラーではありませんでした。

それは 「値の前提条件を考えること」 「失敗の可能性を受け入れること」 「設計で安心を届けるという選択肢があること」

そうした学びの詰まった、やさしいエラーだったのだと思います。

この記事が、「エラーって怖い」から「ちょっとだけ頼れる存在かも」と思ってもらえるきっかけになっていたら嬉しいです。

そして、誰かが「ArithmeticException出た…」と検索したときに、ここで少し安心してもらえたら。

次はどんなエラーと出会えるかな。 それも、ちょっと楽しみだったりしますね。

decopon
decopon

ゼロで割ったら落ちた…?」という、あの不思議で地味なやらかしから始まり、 少しずつ「エラーって設計へのヒントかもしれない」という気づきにつながっていく。

そんな私の小さな歩みが、どこかであなたのつまずきやモヤモヤに寄り添えていたら、これ以上うれしいことはありません。

この先も、予期せぬエラーに出会うことはきっとあると思います。 でも、焦らず向き合いながら「なぜ?」と丁寧に考えていければ、 それはきっと、次のコードをやさしくするヒントになってくれるはずです。

私自身、まだまだ学びの途中です。 一緒に、少しずつ進んでいけたらうれしいです。

コメント

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