Java
初心者

【Java】例外の種類と基本的な処理


例外の種類と対応

APIで提供されている例外クラスは以下のような継承階層にある。


  • Throwable


    • Error


      • Error系例外


        • OutOfMemoryError

        • ClassFormatError ...etc.





    • Excption


      • Exception系例外


        • IOException

        • ConnectException ...etc.



      • RuntimeException系例外


        • NullPointException

        • ArrayIndexOUtOFBOUndsExeception ...etc.







ここでは、特にException系例外について例外対応していく。


try-catchでの基本対応

try-catch文で例外処理を記述できる。

try{

FileWriter fw = new FileWriter("c:¥¥data.txt");
fw.write("hellow!");
}catch(IOException e){
System.exit();
}

例外処理をやらんと、Exception系は以下のようなコンパイルエラーが起きる。

例外 java.io.IOException は報告されません。

スローするにはキャッチまたは、スロー宣言をしなければなりません。

(読んだまんまだが)

try-catchで該当部分を囲むか、

メソッド定義のところでthrow IOExceptionと宣言し、

呼び出し元の方で例外対応するように求められている。


抽象的にキャッチする

catchの条件部分をException eのような書き方をすると、

Exception系例外またはRuntimeException系例外をキャッチする。

Exceptionクラスの子孫クラスを大雑把にキャッチしよう、という意図。

try{

FileWriter fw = new FileWriter("c:¥¥data.txt");
fw.write("hellow!");
}catch(Exception e){
System.out.println("何らかの障害が発生しました"); // 何らかて…
}

「抽象的にキャッチする」という書き方が合っているのかは知らない…。


finally付け

catchの後にfinallyを付ければ、

例外発生の如何に問わず必ず実行したい処理が設定できる。

開いたファイルを閉じる、データベースやネットワークの接続を閉じるなど、後片付けに。

try{

FileWriter fw = new FileWriter("c:¥¥data.txt");
fw.write("hellow!");
}catch(IOException e){
System.out.println("何らかの障害が発生しました");
}finally{
fw.close();
}


自動的にclose()させる

最後にfinallyブロックを書くのが面倒だったら、最初のtry()を書いたりする。

try(

FileWriter fw = new FileWriter("c:¥¥data.txt");
){
fw.write("hellow!");
}catch(IOException e){
System.out.println("何らかの障害が発生しました");
}

これで行くと、最初に開いたdata.txtは自動的にclose()されるらしい。

ただし、java.lang.AutoCloseableインターフェースを実装している型に限る。


throws宣言

メソッドで宣言するときは下記のような書き方。

... メソッド名 throws 例外クラス1, 例外クラス2, ...


Sub.java

public class Sub{

public static void subsub() throws IOException{
FileWriter fw = new FileWriter("date.txt");
fw.write("hello!");
}
}


Main.java

public class Main{

public static void main(Strgin[] args){
try{
// 種々処理があり……
subsub();
}catch(IOException e){
System.exit();
}
}
}

呼び出し先のsubsubメソッドでは処理しないから

呼び出し元のmainメソッドで処理してくれーという感じ。

throwsは例外の送出にも使う。


例外の送出

下記のような書き方をする。単数形になっているので注意。

throw 例外インスタンス;

あるいは

throw 例外インスタンス("エラーメッセージ");


Person.java

Public class Person{

int age;
public class setAge(int Age){
if(age <= 0){
// 0以下だった場合
throw new IllgalArgumentExeception("年齢は正の数にしてください。指定値=" + age);
}
// 正数だった場合
this.age = age;
}
}


Main.java

public class Main{

public static void main(String[] args){
Person p = new Person();
p.setAge(-128); // ここで誤った値のセットを試みる。
}
}

実行結果としては、

Exception in thread "main" java.lang.IllegalArgumentException:年齢は正の数にしてください。指定値=-128

at Person.setAge(Person.java:6)
at Main.main(Main.java:4)

throws文でIllegalArgumentExceptionインスタンスをJVMに投げて報告している。

例外はmainメソッドに投げられるが、ここでは例外をキャッチしていないからJVMが最終的にプログラムを強制停止させる。


オリジナルの例外クラスの定義

既存の例外クラスを継承してオリジナルの例外クラスを作れる。

作り方は一般的な継承方法と同様。

例えば、ドキュメントを読むプログラムかなんかを開発している時、

未対応のドキュメントファイルを読み込んだ時用の例外処理が欲しいな…と。


UnsupportedDocumentFileException.java

public class UnsupportedDocumentFileException extends Exception{

public UnsupportedDocumentFileException(String){
// エラーメッセージを受け取るコンストラクタ
super(msg);
}
}


Main.java

public class Main{

public static void main(String[] args){
try{
// 試験的に例外を投げて...
throw new UnsupportedDocumentFileException
("未対応のドキュメントファイルです");
}catch(Exception e){
e.printStackTrace();
}
}
}

Exception.printStackTrace()は以下の情報を出力してくれる。


  • 投げれらた例外のクラス名

  • コンストラクタで渡された 例外の説明

  • 呼び出し元のメソッドとファイル名・行番号

便利。


参考書籍

スッキリわかるJava入門第二版

Pp.562-595