Java | 1 日 90 分 × 7 日アプリ学習 初級編:例外処理アプリ

Web APP Java
スポンサーリンク

3日目のゴール

3日目のテーマは
「try / catch を“書ける”から、“どこまでを例外に任せて、どこからを自分で防ぐか”まで考えられるようになること」 です。

今日はこういう視点で進めます。

どこまでを「事前チェック」で防ぐか
どこからを「例外」に任せるか
例外が起きたあと、アプリをどう“立て直すか”

1〜2日目の割り算アプリをベースに、
「異常系対策の設計」を一段深くします。


正常系と異常系を“コードの形”で分ける

まずは 2日目版の割り算アプリを確認する

2日目の形を、少しだけ整理して書きます。

import java.util.Scanner;

public class DivideApp {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("1つ目の整数を入力してください: ");
        String aStr = scanner.nextLine();

        System.out.print("2つ目の整数を入力してください: ");
        String bStr = scanner.nextLine();

        try {
            int result = divideStrings(aStr, bStr);
            System.out.println("結果: " + result);
        } catch (NumberFormatException e) {
            System.out.println("整数として解釈できない入力があります。数字だけを入力してください。");
        } catch (ArithmeticException e) {
            System.out.println("0 で割ることはできません。2つ目の数には 0 以外を入力してください。");
        }

        scanner.close();
    }

    static int divideStrings(String aStr, String bStr) {
        int a = Integer.parseInt(aStr);
        int b = Integer.parseInt(bStr);
        return a / b;
    }
}
Java

ここでは、

divideStrings が「失敗しそうな処理をまとめたメソッド」
main が「例外を受け止めて、ユーザーに説明する場所」

という役割分担になっていました。

3日目では、ここに
「事前チェック」と「リトライ(やり直し)」
という考え方を足します。


事前チェックと例外の“役割分担”を考える

なんでも例外に任せるのは、ちょっと雑

今のコードは、
「とりあえず入力を全部 Integer.parseInt に投げて、
ダメなら例外で判断する」という形です。

これは悪くはないのですが、
「本当に全部、例外に任せるのがいいのか?」
という視点を持ってみます。

例えば、
「空文字(何も入力されていない)」は、
例外に任せる前に、自分でチェックできます。

if (aStr == null || aStr.isEmpty() || bStr == null || bStr.isEmpty()) {
    System.out.println("何も入力されていない行があります。");
    scanner.close();
    return;
}
Java

こうすると、

「入力されていない」という“よくあるミス”は
例外に頼らず、自分で分かりやすく扱えるようになります。

事前チェックと例外の線引き

3日目で意識してほしい線引きは、こうです。

「よくある・予想しやすいミス」
→ 事前チェックで防ぐ(空文字、範囲チェックなど)

「どうしても完全には防げないもの」
→ 例外に任せる(ファイルが消されていた、ネットワークが切れたなど)

今回の割り算アプリでいうと、

空文字 → 事前チェック
数字じゃない → 例外(NumberFormatException)
0 で割る → 例外(ArithmeticException)

という分け方が自然です。


リトライ(やり直し)を入れて“アプリっぽく”する

一回ミスったら即終了、はちょっと不親切

今のアプリは、
一度ミスるとそのまま終了します。

現実のアプリなら、
「もう一回入力してもらう」方が自然ですよね。

そこで、
「例外が起きたらメッセージを出して、もう一度入力させる」
という流れを作ってみます。

入力と計算をループで回す

import java.util.Scanner;

public class DivideApp {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("=== 割り算アプリ ===");
            System.out.print("1つ目の整数を入力してください(q で終了): ");
            String aStr = scanner.nextLine();
            if ("q".equalsIgnoreCase(aStr)) {
                System.out.println("終了します。");
                break;
            }

            System.out.print("2つ目の整数を入力してください: ");
            String bStr = scanner.nextLine();

            if (aStr.isEmpty() || bStr.isEmpty()) {
                System.out.println("空の入力があります。もう一度やり直してください。");
                System.out.println();
                continue;
            }

            try {
                int result = divideStrings(aStr, bStr);
                System.out.println("結果: " + result);
            } catch (NumberFormatException e) {
                System.out.println("整数として解釈できない入力があります。数字だけを入力してください。");
            } catch (ArithmeticException e) {
                System.out.println("0 で割ることはできません。2つ目の数には 0 以外を入力してください。");
            }

            System.out.println();
        }

        scanner.close();
    }

    static int divideStrings(String aStr, String bStr) {
        int a = Integer.parseInt(aStr);
        int b = Integer.parseInt(bStr);
        return a / b;
    }
}
Java

ここでの重要ポイントは三つです。

while (true) で「何度でも試せる」形にした
q で終了できるようにした(ユーザーの逃げ道)
空文字は事前チェックで弾き、それ以外は例外に任せた

これで、
「ミスしてもやり直せる、ちょっと優しいアプリ」
になりました。


例外が起きたあと、“アプリをどう続けるか”を決める

例外は「アプリ全体を止める」ためだけのものじゃない

1日目のイメージだと、
「例外が起きたらアプリが落ちる」という印象が強かったと思います。

でも、2〜3日目でやっているのは、

例外が起きる
→ catch で受け止める
→ メッセージを出す
→ アプリ自体は続ける

という流れです。

つまり、
「例外は、アプリを落とすためだけじゃなく、“その操作だけ失敗させる”ためにも使える」
ということです。

今回のループでは、

1回の割り算が失敗しても
次のループで、また新しい入力を受け付けられる

という設計になっています。

どこで“諦めるか”を決めるのも設計

例えば、
「3回連続で失敗したら、アプリを終了する」
というルールを入れることもできます。

int failCount = 0;

while (true) {
    // 入力…

    try {
        int result = divideStrings(aStr, bStr);
        System.out.println("結果: " + result);
        failCount = 0; // 成功したらリセット
    } catch (NumberFormatException e) {
        System.out.println("整数として解釈できない入力があります。数字だけを入力してください。");
        failCount++;
    } catch (ArithmeticException e) {
        System.out.println("0 で割ることはできません。2つ目の数には 0 以外を入力してください。");
        failCount++;
    }

    if (failCount >= 3) {
        System.out.println("エラーが続いたため、アプリを終了します。");
        break;
    }

    System.out.println();
}
Java

ここまで来ると、
例外処理はもう「文法」ではなく、
「アプリの振る舞いを決める設計」 になっているのが分かると思います。


例外メッセージを“人間向けの言葉”に翻訳する

例外オブジェクトには情報が入っている

catch (NumberFormatException e)e には、
例外のメッセージや種類などの情報が入っています。

例えば、こう書くと内部情報も見られます。

catch (NumberFormatException e) {
    System.out.println("整数として解釈できない入力があります。数字だけを入力してください。");
    System.out.println("(開発者向け情報)" + e.getMessage());
}
Java

実際のアプリでは、
ユーザーには優しいメッセージを出しつつ、
ログには e.getMessage() を残す、という使い方をします。

ユーザー向けと開発者向けを分ける、という発想

3日目で持っておいてほしい感覚は、

ユーザーには「何をどう直せばいいか」を伝える
開発者には「何が起きたか」の詳細を残す

という二重構造です。

今回の学習ではログまでは書きませんが、
「例外オブジェクトは、開発者にとってのヒントの塊」
というイメージだけ持っておくと、後で効いてきます。


3日目で絶対に押さえてほしい本質

今日いちばん大事なのは、
「例外処理は“エラーを消すための消しゴム”ではなく、“アプリの振る舞いをデザインするための道具”だ」
という感覚です。

事前チェックで防げるものは防ぐ(空文字など)
それでも起きうる問題は、例外として受け止める
例外が起きたあと、アプリを続けるか・諦めるかを自分で決める
ユーザーには分かりやすく、開発者には詳しく、という視点を持つ

割り算アプリは小さいですが、
中でやっていることは、
大きな業務システムでも同じです。

どこまでを「正常系」として扱うか
どこからを「異常系」として例外に任せるか
異常が起きたとき、アプリをどう“立て直すか”

ここまで考えられるようになった時点で、
あなたはもう「try / catch が書ける人」ではなく、
「例外処理を設計できる人」 の入り口に立っています。

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