Java例外ハンドリング完全攻略:try-catch、finally、throw、throws
Java例外ハンドリングをマスターする
このガイドでは、Javaの例外ハンドリング機構——try-catch、finally、throw、throws——を明確な例とベストプラクティスのヒントで歩みます。
前回のレッスンでJava例外とプログラムフロー中断の理由を紹介しました。それらの例外を優雅にハンドリングすることは、堅牢で保守しやすいコードに不可欠です。
以下はJavaでの例外管理の主要戦略です:
- try…catchブロック
- finallyブロック
- throwとthrowsキーワード
1. try…catchブロックの使用
try…catch構造はJavaのエラーハンドリングモデルの基石です。例外をスローし得るコードをtryブロックに置き、その後で特定例外をcatchします。
try { // 例外をスローし得るコード } catch(Exception e) { // 例外をハンドル }
catch節はtryブロック出現時必須であり、例外を捕捉し適切に応答できます。
例:ArithmeticExceptionのハンドリング
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; System.out.println("Rest of code in try block"); } catch (ArithmeticException e) { System.out.println("ArithmeticException => " + e.getMessage()); } } }
出力**
ArithmeticException => / by zero
このスニペットでは、ゼロ除算がArithmeticExceptionをトリガーします。例外が捕捉され、catchブロックが実行され、tryブロック内の例外以降のコードはスキップされます。
tryブロックが例外なしで完了すれば、catchブロックは単にバイパスされます。
2. finallyブロックの活用
finallyブロックは、例外がスローされたかどうかに関わらず常に実行されます。クリーンアップタスク——ファイルクローズ、リソース解放、ログ記録——に最適です。
1つのtryステートメントにつき1つのfinallyブロックのみ伴えます。
try { // コード } catch (ExceptionType1 e1) { // ハンドル } finally { // 常に実行 }
例:例外後のfinally
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; } catch (ArithmeticException e) { System.out.println("ArithmeticException => " + e.getMessage()); } finally { System.out.println("This is the finally block"); } } }
出力**
ArithmeticException => / by zero This is the finally block
finallyブロックはcatchブロック後に実行され、例外発生時でも重要なクリーンアップコードが確実に実行されます。
ベストプラクティス: 成功・失敗に関わらず実行必須のコード(ストリームクローズ、共有状態リセットなど)にfinallyを使用。
3. 明示的な例外スローとthrows宣言
throwキーワードで例外を手動でスローできます。スローされると、制御は直近の一致するcatchブロックにジャンプします。
例:throwの使用
class Main { public static void divideByZero() { throw new ArithmeticException("Trying to divide by 0"); } public static void main(String[] args) { divideByZero(); } }
出力**
Exception in thread "main" java.lang.ArithmeticException: Trying to divide by 0 at Main.divideByZero(Main.java:5) at Main.main(Main.java:9)
一方throws句は、メソッドが特定の検査例外を伝播し得ることを宣言します。呼び出し元にハンドリングまたはさらなる伝播を義務付けます。
例:ファイルI/Oでのthrows使用
import java.io.*; class Main { // このメソッドがIOExceptionをスローし得ることを宣言 public static void findFile() throws IOException { File newFile = new File("test.txt"); FileInputStream stream = new FileInputStream(newFile); } public static void main(String[] args) { try { findFile(); } catch (IOException e) { System.out.println(e); } } }
出力**
java.io.FileNotFoundException: test.txt (The system cannot find the file specified)
ファイルが存在しない場合、FileInputStreamはFileNotFoundException(IOExceptionのサブクラス)をスローします。findFile()がthrows IOExceptionを宣言しているため、mainメソッドはそれをハンドリング必須です。
メソッドが内部で例外を捕捉しない場合、呼び出し元に潜在的失敗を知らせるためthrowsで宣言しなければなりません。
詳細については、Javaのthrowとthrowsドキュメントを参照。
Java
- Java演算子をマスター:種類、構文、実践例
- Javaコメント:種類、使い方、ベストプラクティス
- Java拡張forループをマスター:構文、例、ベストプラクティス
- Java文字列をマスター:生成、メソッド、ベストプラクティス
- Javaインターフェース完全ガイド:概念、実装、ベストプラクティス
- Java無名インナークラス完全ガイド:定義、構文、実践例
- Java例外ハンドリング実践:try-catch-finallyとリソース管理
- Javaのtry-with-resourcesをマスターする:自動リソース管理の仕組みと活用法
- Javaアノテーション完全ガイド:種類、配置場所、実践例
- Javaアサーション完全ガイド:バグ早期発見とコード信頼性の向上
- Java static 完全解説:変数・メソッド・ブロックの実践例