Edited at

【Java 基本】 Checked Exception と Unchecked Exception について

More than 3 years have passed since last update.


Checked: コンパイル時にチェックされる例外

もしあるメソッド内部のコードがchecked exceptionを投げうる場合は、そのメソッドはその例外をtry/catchで処理するか、throwsキーワードで指定しておく必要がある. (詳細: try/catch か throws Exception か)

例えば、以下のコードを考える. このコードでは、FileReader()を使っているが、FileReader()FileNotFoundExceptionというchecked exceptionを投げうる(throwsしている)ため、このままではコンパイルしない. また、readLine()メソッドや、close()メソッドも使っているが、それらもIOException を投げうる.

import java.io.*;

class Main {
public static void main(String[] args) {
FileReader file = new FileReader("C:\\test\\a.txt");
BufferedReader fileInput = new BufferedReader(file);

// Print first 3 lines of file "C:\test\a.txt"
for (int counter = 0; counter < 3; counter++)
System.out.println(fileInput.readLine());

fileInput.close();
}
}

上記のコードをコンパイルしようとすると、以下のようなエラーになる.

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - 

unreported exception java.io.FileNotFoundException; must be caught or declared to be
thrown
at Main.main(Main.java:5)

この問題を解決するためには、 throwsで例外のリストを指定するか、try/catchを使うことである. 今回の例では、 FileNotFoundExceptionIOExceptionのサブクラスなので、以下のようにIOExceptionのみを指定すれば良い.

import java.io.*;

class Main {
public static void main(String[] args) throws IOException {
FileReader file = new FileReader("C:\\test\\a.txt");
BufferedReader fileInput = new BufferedReader(file);

// Print first 3 lines of file "C:\test\a.txt"
for (int counter = 0; counter < 3; counter++)
System.out.println(fileInput.readLine());

fileInput.close();
}
}


Unchecked: コンパイル時にチェックされない例外

C++では全ての例外がuncheckedなため、コンパイラに例外処理や例外指定を要求されることはなく、その対処は書き手に委ねられている.

Javaでは、throwableなクラスの中で、ErrorクラスとRuntimeExceptionクラス以下の例外のみunchecked exceptionで、他は全てcheckkedである.

以下のコードは、実行時にArithmeticExceptionを投げるが、コンパイルはできる. ArithmeticExceptionがunchecked exceptionであるからである.

class Main {

public static void main(String args[]) {
int x = 0;
int y = 10;
int z = y/x;
}
}


なぜchecked/uncheckedの2つのタイプを持つのか?


起こりうる例外を指定するのはメソッドのインターフェースの責務

メソッド無いうで投げられうるchecked exceptionを全て指定するのは、メソッドのインターフェースの責務であり、そのメソッドを呼び出す元は、どのような例外が投げられうるのかを知ることで、対処できる. もし全ての例外がuncheckedであれば、APIの呼び出し元にとっては大変である.

引数、返り値とならんで、インターフェース定義の一部に、例外の指定もあると考えている.


APIクライアントが処理できない/するべきではない問題のみ、unchecked exceptionを用いる

例外を指定することが良いことならば、なぜunchecked exceptionは存在するのか?Runtime Exceptionも指定すれば?と思うかもしれない.

しかし、APIの呼び出し元が処理することができなかったり、処理することが望ましくない問題に対して、unchecked exceptionを投げる.

またRuntime exceptionはどこでも起きうるため、全てに対応を入れたら、コードの可読性を下げてしまう.


RuntimeExceptionを投げるタイミング

メソッドの呼び出し方が誤っている時にRuntime Exceptionを出すのが、一つの慣習である.

単に呼び出し元での例外処理が面倒だからという理由でRuntimeExceptionを使うことは、なるべく避けたい.


例外をcheckedにすべきか?uncheckedにすべきか?

APIクライアント(メソッドの呼び出し元)が例外を処理できる/すべきケースではcheckedを、そうでない場合はuncheckedを使用するべきである.


参考:

* Checked vs Unchecked Exceptions in Java

* Unchecked Exceptions — The Controversy