try-catchとは?
Javaでプログラムを作るとき、思いがけない場面でエラーが起きることがあります。たとえば、存在しないファイルを開こうとしたり、数字ではない文字列を数値に変換しようとしたりすると、プログラムはそのまま止まってしまいます。これでは利用者に不便をかけてしまいます。
こうした問題に対応する仕組みが「例外処理」であり、Javaでそれを実現する代表的な構文がtry-catchです。
tryブロックには、エラーが起きる可能性のある処理を書きます。そしてcatchブロックには、エラーが起きたときに行う処理を書きます。tryの中でエラーが発生すると、処理はcatchに移り、エラーの内容に応じた対応が実行されます。エラーが起きなければcatchの中身は実行されません。
また、finallyというブロックを追加することもできます。こちらは処理途中で例外が発生した場合でも実行されます。ファイルを閉じたり、接続を切ったりといった「後片付け」をここに書くのが一般的です。
try-catchを使うことで、エラーが発生した場合でも適切な処理を継続し、 適切なメッセージを表示したり代替の処理に切り替えたりできるようになります。
基本構文
try-catchの基本的な構造を理解するために、まずシンプルなコード例を見てみましょう。tryブロックにはエラーが発生する可能性のある処理を 、catchブロックにはエラーが発生したときの処理を書きます。以下では、よく使われるパターンを2つ紹介します。
パターン1:基本的なtry-catch
出力結果
エラーが発生しました: / by zerocatchの括弧の中には、どの種類のエラーを受け取るかを指定します。ここではArithmeticExceptionというエラーを指定しています。コード中のeは発生した例外の情報を格納する変数です。e.getMessage()を使うと、例外の内容をメッセージとして取得できます。
パターン2:finallyブロックを追加した構文
出力結果
結果: 5
処理が終了しましたこのコードではエラーが起きていないため、catchの中は実行されません。一方、finallyは例外が発生したかどうかに関係なく実行されます。終了処理や後片付けを確実に行いたいときに、このブロックを活用します。
実用例
ここからは、実際の開発でよく遭遇する場面を想定したコード例を紹介します。それぞれのコードで、どんな状況でtry-catchが役立つのかをイメージしながら読んでみてください。各コード例には出力結果も付けているので、動作を確認しながら理解を深められます。
ゼロ除算エラーの処理
ある数をゼロで割ろうとすると、JavaではArithmeticExceptionが発生します。ゼロ除算はプログラムの中で意図せず起きやすいエラーのひとつです。このコードでは、ゼロで割る処理をtry-catchで安全に扱う例を示しています。
出力結果
ゼロでは割れません: / by zero変数bがゼロなので、a / bの時点でArithmeticExceptionが発生します。catchがそれを受け取り、エラーメッセージを表示します。実際の計算処理を含む場面では、入力値のチェックと組み合わせて使うとさらに安全です。
配列の範囲外アクセスの処理
配列にアクセスするとき、存在しないインデックスを指定するとArrayIndexOutOfBoundsExceptionが発生します。ネコの鳴き声の配列を例に、範囲外アクセスのエラー処理を見てみましょう。
出力結果
その番号は存在しません: Index 5 out of bounds for length 3配列catsには3つの要素しか入っていませんが、インデックス5を指定しているため例外が発生します。catchがそれを捕まえて、エラーの内容を表示しています。
配列を扱うプログラムでは、インデックスが配列の長さを超えないかどうかを確認する処理と合わせて使うと、より安全なコードになります。
数値変換エラーの処理
文字列を整数に変換するInteger.parseInt()は、整数ではない文字列を渡すとNumberFormatExceptionを投げます。このコードでは、変換できない文字列を渡した場合のエラー処理を示します。
出力結果
数値に変換できません: For input string: "イヌ"「イヌ」という文字列は数値に変換できないため、NumberFormatExceptionが発生します。ユーザーからの入力を数値として扱う処理では、このエラーが起きやすいため、try-catchによる例外処理がよく使われます。
エラーが起きたときには入力し直してもらうよう案内するなど、次のアクションにつなげる処理を追加すると実用的です。
ファイル読み込みエラーの処理
存在しないファイルを読み込もうとすると、FileNotFoundException が発生します。 FileNotFoundException は IOException のサブクラス(子クラス)であるため、コード内では IOException をキャッチすることで、ファイルが見つからないエラーも包括的に処理できます。
IOException(親):汎用的な入出力エラー
FileNotFoundException(子):ファイルが見つからないエラー
出力結果
ファイルを読み込めませんでした: animals.txt (No such file or directory)animals.txtというファイルが存在しないため、FileNotFoundException(IOExceptionのサブクラス)が発生します。catchでIOExceptionを指定することで、ファイル操作に関連するさまざまな入出力エラーをまとめて捕捉できます。ファイルを扱うコードで、頻繁に登場するパターンです。
複数の例外を個別にキャッチする処理
1つのtryブロックに対して、複数のcatchブロックを書くことができます。それぞれ異なる種類のエラーを別々に処理できるため、エラーの種類に応じてメッセージや対処を変えたいときに役立ちます。
出力結果
数値を入力してください: For input string: "空"inputが「空」という文字列なので、Integer.parseInt()でNumberFormatExceptionが発生し、最初のcatchが実行されます。もしinputが「5」であれば、配列の範囲外として2つ目のcatchが実行されます。
このように複数のcatchを書くことで、エラーの種類ごとに適切な対応ができます。
finallyブロックを使ったクローズ処理
finallyブロックには、処理の成功・失敗に関係なく最後に実行したい処理を書きます。ファイルを閉じる処理や接続を切断する処理など、開発の現場でも使われることが多い構文です。
出力結果
ウサギのデータを処理します
処理結果: 20
リソースを解放しましたエラーが発生しなかったため、catchは実行されていませんが、finallyは確実に実行されています。このように、後片付けの処理をfinallyに書いておくと、エラーが起きても起きなくても処理が漏れる心配がありません。
実際のアプリケーション開発では、接続の切断やログの出力などをfinallyに書くことが多くあります。
カスタム例外のスローとキャッチ
Javaでは、自分でオリジナルの例外クラスを作ることができます。これを「カスタム例外」といいます。アプリケーション固有のエラーを表現したいときに使います。
throwsは、このメソッドが例外を送出する可能性があることを宣言するために使用します。実際に例外を発生させる処理はthrowで行います。 末尾の”s”の有無にご注意ください。
出力結果
スズメはトリです
例外が発生しました: クマはトリではありませんToriExceptionという独自の例外クラスをExceptionを継承して定義しています。checkBird()メソッドの中で条件に合わない場合にthrowで例外を発生させ、呼び出し元のtry-catchでそれを受け取っています。カスタム例外を使うと、エラーの意味をコードの中で明確に表現できるようになります。
まとめ
Java try-catchはプログラムの実行中に起きるエラーに対応するための構文です。tryブロックにエラーが起きうる処理を書き、catchブロックでそのエラーを受け取って対処することで、プログラムが突然止まることなく動き続けられるようになります。また、finallyブロックを使えば、エラーの有無にかかわらず確実に後処理を実行できます。
try-catchの活躍する場面
- ユーザー入力処理:数値変換や文字列解析など、不正入力が起きやすい処理
- ファイル・外部リソース操作:ファイル読み書きやDB接続など外部I/Oを扱う処理
- 業務ロジックの複合処理:複雑な処理が必要で、例外が混在するケース
重要なポイント
- catchで適切な例外クラスを正しく指定し、処理を分岐させる
- finallyを用い、接続やファイルクローズを確実に実行し、後処理漏れを防ぐ
- 独自の例外クラスを定義することで、アプリ固有のエラーを明確化する
try-catchを適切に使うことで例外を適切に処理でき、利用者にとって扱いやすいプログラムを作れるようになります。
最初はどこに書けばよいか迷うこともありますが、まずは処理の中で例外が発生しそうな箇所をtryで囲む練習から始めてみましょう。
コード例を参考にしながら、実際に手を動かして試してみてください。