構造化例外処理

プログラミングの中でエラー処理は重要です。
プログラムは行いたいことを実現するための物ですが、何かを実現する作業の中には必ず外乱が発生します。それらの外乱を事前に想定して、外乱が発生した場合の対処がエラー処理です。だからと言って処理手順ごとにプログラマーが思い思いにエラー処理を行っていたら、プログラムが何を行いたいのか、処理の流れが分かりにくくなってしまいます。

そこでJavaではプログラムの可読性を高めるため、行いたい処理とエラー処理を分離し、行いたい処理の中に意味合いの違うエラー処理が混在しないように、二つを構造化して分離するプログラミング手法「構造化例外処理」が推奨されます。
ここで、「エラー処理」と「例外処理」の意味が違うように感じますが、Javaでは広義のエラーを狭義のエラーと例外に分け、プログラムによる対処が可能な例外について処理機構を作り、その処理機構が狭義のエラーも扱えるようにしているため、広義のエラー全体を扱える処理を例外処理と呼んでいます。
狭義のエラーや例外の詳細については例外処理を参照ください。

「構造化例外処理」の構文はtry-catch-finallyの三つのブロックで構成され、tryブロックに行いたい処理、catchブロックに処理によって発生する可能性のある例外の回復処理、そしてfinallyブロックに例外発生の有無にかかわらず実行したい処理を記述します。
さらに例外が発生した場合、その発生したメソッド内でキャッチして例外を処理することも、メソッド名に続けてthrows宣言を行い、例外処理をメソッドの呼び出しもとに移譲することも出来ます。なお、例外処理の移譲によってメソッド呼び出しの大元で例外を一元管理して処理することが出来ます。

try ブロック内には、複数の文を記述できます。もし例外が発生したらtry ブロック内の以降の処理はスキップされ、すぐに対応するcatch ブロックに制御が移ります
catch ブロックの目的はプログラムを正常な状態に復帰させることで、キャッチできる例外はすべての例外のルートクラスであるThrowableクラス、例外処理が必須のExceptionクラスだけでなく、例外処理が必須ではないErrorクラスやRuntimeExceptionクラスもキャッチできます。catchブロックの処理が終了すると「不具合は対処された」として、finallyブロックの処理に移ります。なお、throws宣言して例外をメソッドの呼び出し元に移譲する場合にはcatchブロックは省略できます。
finallyブロックは必ず実行されるブロックであり、例外をthrows宣言している場合、例外が移譲される前に実行されます。またcatchブロックにreturn文がある場合でも、return処理の前にfinallyブロックが実行され、その後catchブロックのreturnが実行されます。
try-catch-finallyの構文は、各ブロックの順序を変更することはできません。誤った順序で記述するとコンパイルエラーになります。tryブロックとfinallyブロックは1つずつしか記述できず、複数記述するとコンパイルエラーになります。一方、catchブロックは複数記述できます。
なお、catchブロックを複数記述する場合はcatchする例外の順序はサブクラスを先頭にする必要があります。これは例外クラスのインスタンスも、ほかのクラスと同様にポリモーフィズムが成り立ち、サブクラスの例外クラスのcatchはスーパークラスの例外処理がcatch可能であり、結果サブクラスの例外処理がスーパークラスの例外処理の後に記述されていると、サブクラスの例外処理は常に実行されない事になるからです。このような場合、コンパイラーは到達不可能なコードをあるとして、コンパイルエラーを発生します。

複数のtry-catchがネストしている場合、スローされた例外を受け取るのは、その例外に対応したもっとも近いcatch ブロックです。ネスト階層ごとにfinallyブロックがある場合は、ネストの内側から順にすべてのfinallyブロックが実行されます。

カテゴリー: Java タグ: , , , , パーマリンク