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 が書ける人」ではなく、
「例外処理を設計できる人」 の入り口に立っています。
