javaの例外処理について。

・Exceptionを継承して例外をラッピングできる自作クラスMyException、RuntimeExceptionを継承して例外をラッピングできる自作クラスMyRuntimeExceptionがあるとする。

こんなの
package test.exception.myexception;

public class MyException extends Exception {
private static final long serialVersionUID = 1L;

public MyException() {
super();}

public MyException(String message) {
super(message);}

public MyException(String message, Throwable cause) {
super(message, cause);}

public MyException(Throwable cause) {
super(cause);
}}

・Exceptionはチェック例外、RuntimeExceptionは非チェック例外。

・RuntimeException、MyRuntimeException、Exceptionをcatch節で書く場合、try節で何も書かなくてもコンパイルエラーにならない。MyExceptionやExceptionのサブクラスのチェック例外は、到達不能なコードとなりコンパイルエラーになる。つまり、例外が起こる可能性がないとチェック例外の例外処理は書くことはできない。ExceptionはサブクラスにRuntimeExceptionがあるからおっけ。

・継承関係は、Exception←RuntimeException
例外(クラス図とか)
Exception←IOException←FileNotFoundException

・チェック例外のException、MyExceptinを(newして)throwする場合、tryで囲むか(意味なし)、メソッドでthrows宣言を追加しなければ、コンパイルエラーになる。


・非チェック例外を、放置しておくとどうなるか?
⇒throws宣言を書かなくても、勝手にthrowされる
throwsリスト

・finally節では確実なリソースの開放やテクニカルな場面につかう。リソースの開放はまじめにやると面倒くさい。
参考@itの記事

・自作例外のコンストラクタの引数にjava.lan.Throwableを使うのは元の例外をラッピングするため、元の原因を追跡できるため、何が原因で例外を発生したかを把握できるようにするため。例外が発生しない場面で自作例外をnewしてthrowする場合のコンストラクタは引数をエラーメッセージなどにしておく。
@it参考記事。何が原因で~

・チェック例外、非チェック例外は、自作例外MyException,MyRuntimeExceptionで直接catchできない。逆はできる。RuntimeExceptionはExceptionでcatchできる。継承関係を考えればわかる。なので、個々の例外でcatchしてあげて(面倒ならException,RuntimeExceptionでcatchする)、自作例外でラッピングしてあげてthrowする。こうすれば例外の種類が沢山ある面倒な例外処理が、(上位の層では)自作例外だけでまとめられる(自作例外に何か情報を詰め込む必要がないならば、Exceptionでも充分)。Error系例外はcatchしても復旧不可能な例外が多いので、例外処理はあまりされない。例えばOutOfMemoeryException。


・チェック例外、非チェック例外をそれぞれ、MyExceptoin、MyRuntimeExctpionでラッピングできるか?
⇒できる。上で書いたMyException自作例外みたいに、コンストラクタの引数をThrowableにすればできる。ThrowableはExceptionの親クラス。Exception系をMyRuntimeExceptionにラッピングできるし、RuntimeException系をMyExceptionにラッピングもできる。つまり、例外処理でチェック例外を潰して非チェック例外にできる。これが良いかどうかはわからん。

チェック例外MyExceptionが発生するメソッドは、非チェック例外MyRuntimeExcpetionでcatch処理できない。継承関係であたりまえ。逆のMyRuntimeExceptionが発生するメソッドはMyExceptionでcatchできない。これは、継承関係以前に、到達不能コードであるため。だから、両例外を自作してそれを使い分けるアプリを作る場合、受け側のメソッドでは両方を処理してあげなくてはいけないので面倒。MyRuntimeExceptionが日チェックなので無視できるが。

■考察。アプリでは、例外処理、自作例外はどうするのがベストか?
・自作例外はMyException,MyRuntimeExceptionどちらかを作る。本当は両方作り使い分けた方が良いが、さすがに面倒。チェック例外、非チェック例外のどちらもラッピングするための自作例外はMyException,MyRuntimeExceptoinどちらでもいい気がする。どっちがいいんだろう?と考えたけど・・・
・チェック例外はcatchして自作例外にラッピング。ここで処理を継続するかしないかでわける。処理を終了したい、ログを出力したいなら、なるべくその場所は一か所にまとめたい。その場合、throwしてプログラムの入り口でその処理をしてあげるのが一番かな。
・非チェック例外をcatchしょりするかどうかはケースバイケース。特にぬるぽは。どうしてもミスが許されない場面なら、確実に例外処理をしてログ出力して処理を停止する。そうでない場合は例外処理しない方がいいかも。例外処理しなければ、開発時に例外が発生し、それがすぐに解るので、すぐに直せる。例外処理をした場合、なんか画面の日付が表示されてないんだけど何で?みたいな感じになり追わないといけないとなくなり、デバッグが面倒。最低でも例外処理でcatchした時はログをはくべき。例外処理ではないけど、例外を未然に防ぐ処理で、if(obj != null){}と書き、かつobjがnullの場合になにかしらの処理をしなければならない場面なんてのが最悪だ。マジで何もするな。
・バッチなどのクリティカルな部品は最終的にcatchする例外は自作例外だけじゃなく、Exctpionでもcatchし、必ずファイルorDBなどの永続化できるモノにログをはくようにする。Excpetionも書いておかないと、漏れたRuntimeExcpetionが標準出力して終わる。Error系はどうなんだろう?
・DAOとかService層毎に自作例外を作るのはいいかも。けど、これも面倒。
・webアプリなどのフレームワークなどでは一番上位の層のControllerクラスでcatchして適切な処理をしたりする。controllerでもthrowして例外handlerクラスに任せてもいい。
・特別なケース、例えば、ログインに失敗した時などはそれ用の自作例外を作るのがいいかも。LoginExceptionとか。そして、一番上の階層でLoginExceptionは個別にcatchして処理する。戻り値で判断するよりは楽。戻り値とexception、どちらで判断するかはケースバイケース

あまりまとまってない・・

■参考 
throwsとtry catch(チェック例外と非チェック例外)
javaの例外(Hishidama)
javaの例外処理で知らないと損する7つのテクニック