Javaの例外

Java本格入門シリーズ。



今回は例外について読んだので、それのメモ。


例外は大きく3つ

1.検査例外(チェック例外) - Exception

2.実行時例外(非チェック例外) - RuntimeException

3.エラー(Error)




例外を表す3つのクラス

java.lang.Exceptionクラス

検査例外をあらわすクラス

このクラスを継承した例外は

・プログラム中で捕捉する(try~catch)

・発生するメソッド宣言でthrows節を記述する



throws宣言することで、どのメソッドでどんな例外が発生するのかがわかりやすくなったり、例外処理を書かないとコンパイルエラーになるので、例外の見逃しがなくなる。



一方で、tyr~catchブロックが必須になったりと、プログラムがやや重厚になりやすいので賛否両論ある。

java.lang.RuntimeExceptionクラス

実行時の例外をあらわすクラス。Exceptionクラスを継承している。



・プログラム中に捕捉する必要なし(try~catchが必須ではない)

・throws宣言も必須ではない。



捕捉しなかったら、Java VMに到達した時に「そのスレッドが終了する」


java.lang.Errorクラス

基本、アプリケーションでは捕捉すべきでない重大な問題

を示すクラス。



try~catchもthrowsも必須ではない。



だいたいアプリケーションに異常状態になっているので、捕捉せずにプログラムを終了させるべき。



例として、OutOfMemoryErrorクラス(メモリ不足)があるが、この状態でアプリケーションをそのままにしておくのはよろしくない。


try~catch=finally

try{

  //SomeException例外が発生する可能性のあるコードを含む処理

} catch(SomeException ex){

  //SomeException例外をcatchした時の処理

} finally {

  //try~catchブロックが終了したら必ず実行するべき処理

}

try~with-resources

try(InputStream is = File.newInputStream(Path)){

  //is.read(contens)

  //contensに対する処理。

} catch(IOException ex){

  //例外を捕捉した場合の処理。

}


マルチキャッチ

発生する例外ごとに処理をわけたい場合は複数のcatchを書いて処理できる。

try{

  //例外Aあるいは例外Bが発生する可能性のある処理。

} catch(例外A){

  //例外Aが発生した時の処理

} catch(例外B){

  //例外Bが発生した時の処理

}

複数例外をまとめることもできる。

try{

  //例外Aあるいは例外Bあるいは例外Cが発生する可能性のある処理。

} catch (例外A) {

  //例外Aが起きた時の処理

} catch (例外B |

         例外C) {

  //例外Bあるいは例外Cが起きた時の処理

}


例外処理のポイント

・エラーコードをreturnしない
javaは標準で例外機構を持っているので、エラーが発生したら例外を発生させること
正常に終了したらオブジェクトをreturnすればいい。
成功も失敗もreturnすると呼び出し元で条件分岐処理などが必要になってくる。
(もともとIsXxxなどの判定処理を意図したメソッドなら判定自体が成功したということでthrowしない方がいいケースもある)


・例外を揉み消さない。
catchブロックの中に何も書いていないケースがあったりするが、それはNG。
例外が起きたことすら気づかず、重大な問題を起こしかねない。

1.ログ出力をする
スタックトレースまで残すように

2.処理を継続するか判断する
処理を継続させた時に、次の処理でオブジェクトがnullになっていてぬるぽを発生させる可能性があったりするので、
基本的には例外が発生したら後続処理は中止させ、復旧or上位メソッドにthrowするべき。




thorws Exceptiionは悲劇の元

1.呼び出し元でExceptionを捕捉しないといけなくなる
メソッド呼び出しの階層が深くなると、上位の呼び出し元は
「なぜ例外を捕捉しなければいけないのかがわからない」状態になる

2.途中でIOExceptionなどの具体的な例外が発生しても Exceptionに巻き込まれしまう。
Exceptionは基底クラスなので、Exceptionでそのまま宣言できる。

そうなるとどんな例外が発生するのかは、コードを読んだだけではわからなくなる。



3.途中でRuntimeExceptionが発生しても、Exceptionに巻き込まれてしまう。

実行時例外(必ずしも捕捉する必要はない)でも捕捉しないといけなくなってしまう。
検査例外だと思って処理してしまう可能性がある。
重要な実行時例外を見逃してしまう可能性がある。



その他メモ

・例外が発生する(可能性がある)箇所。いわゆる末端箇所では「例外を発生させるだけ」に留めた方がいい

・処理の流れを判断する箇所で例外を捕捉するのが良い。

独自例外を作るポイントとして
・業務に特化した処理
フレームワークやシステムで共通的な例外処理をする場合
などになる。

ラムダ式で発生した例外はラムダ式の中で処理する(中にtry~catchを書く)