try の全体像
try は「失敗しうる処理を囲み、例外が起きたときに安全に対応する」ための構文です。基本は try の中に通常処理を書き、失敗したら catch で受け止め、最後の後始末を finally で必ず実行します。ファイルやソケットなど外部リソースを扱うときは、try-with-resources を使うと自動でクローズされ、例外時でも漏れません。
try-catch-finally の基本
例外を捕まえてメッセージを出す
try {
int x = Integer.parseInt("123");
System.out.println("OK: " + x);
} catch (NumberFormatException e) {
System.err.println("数値に変換できません: " + e.getMessage());
}
Javatry の中で例外が発生すると、その型に一致する catch に処理が飛びます。catch は「何が起きたのか」を具体的に伝える役割で、復旧手段があるならそこで行います。
後始末は finally で必ず実行
java.io.BufferedReader br = null;
try {
br = new java.io.BufferedReader(new java.io.FileReader("input.txt"));
System.out.println(br.readLine());
} catch (java.io.IOException e) {
System.err.println("読み込み失敗: " + e.getMessage());
} finally {
if (br != null) try { br.close(); } catch (java.io.IOException ignored) {}
}
Javafinally は例外の有無に関わらず必ず実行されます。手動クローズが必要なリソースの「後始末」はここに置きます。
try-with-resources(自動クローズ)
最短で安全に後始末する
import java.nio.file.*;
import java.io.*;
public class ReadFirstLine {
public static String firstLine(Path p) throws IOException {
try (var br = Files.newBufferedReader(p)) {
return br.readLine();
} // ここで自動 close(例外時も必ず)
}
}
Java括弧内の変数は AutoCloseable を実装している必要があります。ファイル、ソケット、DB接続などはこれで管理すると、例外時でも確実にクローズされ、漏れがありません。
例外の抑制情報(サプレスト)に注意
try-with-resources では、クローズ時の例外が「サプレスト例外」として本体の例外に付与されます。ログやスタックトレースで「suppressed」の項目も確認すると原因特定が速くなります。
catch の順序と複数捕捉
具体的な例外から先に並べる
try {
// I/O処理
} catch (java.io.FileNotFoundException e) {
System.err.println("ファイルが存在しません");
} catch (java.io.IOException e) {
System.err.println("I/O失敗");
}
JavaFileNotFoundException は IOException のサブクラスです。サブクラスを先に、親クラスを後に並べます。逆順だと到達不能でコンパイルエラーになります。
マルチキャッチで簡潔に書く
try {
// 変換+I/O処理
} catch (NumberFormatException | java.io.IOException e) {
System.err.println("入力エラー: " + e.getMessage());
}
Java同じ対処でよい複数の例外は、| でまとめて捕捉できます。
throws と再スロー、例外の連鎖
ここでは処理せず、呼び出し側へ委ねる
void load(java.nio.file.Path p) throws java.io.IOException {
try (var br = java.nio.file.Files.newBufferedReader(p)) {
System.out.println(br.readLine());
}
}
Java回復をこの層で行わない判断なら、throws で上位へ伝えます。アプリの入口など一箇所にエラーハンドリングを集約すると、ログやユーザー通知が整理されます。
原因例外をつないで意味を保つ
try {
service.process(req);
} catch (java.sql.SQLException e) {
throw new IllegalStateException("DB処理失敗: reqId=" + req.id(), e);
}
Java新しい例外へ包むときは、必ず原因(e)を渡して連鎖させます。根本原因のスタックトレースが失われないため、運用での解析が容易になります。
よくある落とし穴と安全な書き方(重要ポイントの深掘り)
例外の握り潰しは厳禁
何もしない catch は問題を隠します。少なくともログは出すか、ユーザー向けメッセージ・再スロー・既定動作のいずれかを設計します。
catch の範囲は必要最小限に
大きく try を囲み過ぎると、どこで失敗したかが曖昧になります。「失敗しうる最小の塊」を try にし、成功パスの読みやすさも保ちます。
例外で通常の分岐を作らない
例外は「想定外の異常」に使う道具です。通常の検証は if で前倒しに行い、契約違反は IllegalArgumentException などで明確に弾きます。
変数の初期化とスコープに注意
try の内外で使う変数は、外で宣言します。例外でスキップされたときに未初期化参照が起きないよう、代入と使用の位置関係を明確にします。
String line;
try (var br = java.nio.file.Files.newBufferedReader(java.nio.file.Path.of("a.txt"))) {
line = br.readLine();
} catch (java.io.IOException e) {
line = ""; // 既定値にフォールバック
}
System.out.println(line);
Java例題で身につける
例 1: 入力を検証し、例外を減らす
public class Price {
public static int taxed(int subtotal, double taxRate) {
if (subtotal < 0) throw new IllegalArgumentException("subtotal must be >= 0");
if (taxRate < 0 || taxRate > 1) throw new IllegalArgumentException("taxRate must be 0..1");
return (int) Math.round(subtotal * (1 + taxRate));
}
}
Java通常の前提違反は if で弾き、例外は「本当に異常な外部要因」に集中させます。
例 2: ファイル読込とエラー通知の基本形
import java.nio.file.*;
import java.io.*;
public class Reader {
static String readFirst(Path p) throws IOException {
try (var br = Files.newBufferedReader(p)) {
return br.readLine();
}
}
public static void main(String[] args) {
try {
System.out.println(readFirst(Path.of("input.txt")));
} catch (IOException e) {
System.err.println("読込失敗: path=" + pToStringSafe(e));
e.printStackTrace(); // 運用ログへ
}
}
static String pToStringSafe(Exception e) { return e.getMessage(); }
}
Java例 3: マルチキャッチでシンプルにフォールバック
public class ParseAndLoad {
public static void main(String[] args) {
try {
int port = Integer.parseInt(System.getenv("APP_PORT"));
java.net.ServerSocket server = new java.net.ServerSocket(port);
System.out.println("start on " + port);
} catch (NumberFormatException | java.io.IOException e) {
System.err.println("設定不正または起動失敗: " + e.getMessage());
System.out.println("既定ポート 8080 で再試行します");
}
}
}
Java仕上げのアドバイス(重要部分のまとめ)
try は「失敗しうる最小の塊」を囲み、catch は具体的に対応し、finally(または try-with-resources)で必ず後始末するのが基本です。サブクラスの例外を先に並べ、同じ対処ならマルチキャッチで簡潔に。ログは一箇所で責任を持って出し、原因連鎖を保つ。通常の分岐は if で前倒しに検証し、例外は本当に異常な事態へ限定する。この型が身につくと、落ちても壊れないコードに変わります。
