3秒でわかる
失敗するかもしれない処理を囲み、例外が起きたときの後始末を書くための構文。異常時にプログラムを落とさず、利用者へ意味のある応答を返すために使います。
もう少し詳しく
どういうものか
try-catch は、例外が発生しうる処理を try ブロックに入れ、発生したときの処理を catch ブロックに書く構文です。try の途中で例外が投げられると、そこから先の行は実行されず、型の合う catch へ制御が移ります。
Java では finally を付けられます。例外が起きても起きなくても最後に必ず通るため、後始末を書く場所として使います。catch は複数並べられ、上から順に型が照合されます。
なぜ必要か
ファイルが無い、通信が切れた、数値に変換できない文字列が来た、といった事態は正常な処理の流れでは避けられません。戻り値でエラーを表す方式だと、呼び出し側が確認を忘れた瞬間に間違った値のまま処理が進みます。例外は確認を忘れると処理が止まるため、握りつぶしにくいという性質があります。
具体例
import java.nio.file.*;
import java.io.<a href="/glossary/ioexception" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">IOException</a>;
public class Main {
public static void main(String[] args) {
try {
String text = Files.readString(Path.of("data.txt"));
int value = <a href="/glossary/integer-parseint" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">Integer.parseInt</a>(text.trim());
System.out.println(value * 2);
} catch (NoSuchFileException e) {
System.out.println("data.txt が見つかりません");
} catch (NumberFormatException e) {
System.out.println("数値として読めません " + e.getMessage());
} catch (IOException e) {
System.out.println("読み込みに失敗しました");
} finally {
System.out.println("処理を終了します");
}
}
}つまずきやすいところ
最も多い失敗は、catch の中を空にすることです。コンパイルは通りますが、異常が起きても何も起きなかったように処理が続き、原因を後から追えなくなります。少なくともログに例外の内容を残します。
catch の順番も注意が要ります。catch (Exception e) を先に書くと、後ろに書いた具体的な型には決して到達せず、Java ではコンパイルエラーになります。広い型は必ず最後です。
もう 1 つ、try の中を長くしすぎると、どの行で失敗したのか分からない catch ができあがります。失敗しうる処理だけを囲むのが原則です。
似た用語との違い
Java の例外は 2 系統に分かれます。IOException のような検査例外は、catch するか throws を宣言しないとコンパイルが通りません。NullPointerException のような非検査例外は宣言不要ですが、その多くはプログラムの誤りなので、catch でごまかさず原因を直します。
覚え方
try は「やってみる」、catch は「落ちてきたものを受け止める」、finally は「片付け」です。役割が 3 つに分かれていると考えます。