Java 例外オブジェクトの生成について
ここでは簡単な計算機プログラムを作成して例外処理について考察します。
Part1
次の計算機クラス(Calculator)は0による除算時に例外をスローします。
計算機クラス
package example; public class Calculator { public int divide(int x, int y){ return x / y; } }
引数 y が0のとき例外が発生します。
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } }
実行結果
Exception in thread "main" java.lang.ArithmeticException: / by zero at example.Calculator.divide(Calculator.java:6) at example.Main.main(Main.java:8)
Arithmeticとは "算数" という意味です。
Part2
次に独自の例外クラス(CalculatorException)を作成してみます。
計算機例外クラス
package example; public class CalculatorException extends Exception { }
例外クラスを作成する場合はExceptionクラス(およびそのサブクラス)を継承します。Exceptionクラスを継承すると検査例外クラスになります。RuntimeExceptionを継承した場合は実行時例外クラスになります。
計算機クラス
package example; public class Calculator { public int divide(int x, int y) throws CalculatorException{ if (y == 0) { throw new CalculatorException(); } return x / y; } }
CalculatorExceptionは検査例外クラスであるため、例外処理(try-catch or throws)が必須になります。
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); try { // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } catch (CalculatorException e) { e.printStackTrace(); } } }
CalculatorクラスのdivideメソッドはCalculatorExceptionをスローします。CalculatorExceptionは検査例外クラスであるため、例外処理(try-catch or throws)が必須になります。
実行結果
example.CalculatorException at example.Calculator.divide(Calculator.java:7) at example.Main.main(Main.java:8)
Part1の実行結果と比較してみましょう。
e.printStackTrace();
変数eに対してprintStackTraceというメソッドを呼び出しているだけです。変数eはCalculatorException型の変数です。printStackTraceメソッドは例外情報(例外クラス名、メッセージ)とスタックトレース(メソッド呼び出しの履歴)を出力します。
例外クラス名: メッセージ スタックトレース .. スタックトレース
Part2.5
独自の例外クラス(CalculatorException)にはメッセージを含むこともできます。
計算機例外クラス
package example; public class CalculatorException extends Exception { public CalculatorException(String message){ super(message); } }
スーパークラス(Exception)のコンストラクタにメッセージを設定すると、printStackTraceメソッドの中にメッセージを含むことができます。また設定したメッセージはgetMessageメソッドによって取得可能です。
計算機クラス
package example; public class Calculator { public int divide(int x, int y) throws CalculatorException{ if (y == 0) { throw new CalculatorException("/ by 0"); } return x / y; } }
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); try { // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } catch (CalculatorException e) { e.printStackTrace(); // System.out.println(e.getMessage()); } } }
実行結果
example.CalculatorException: / by 0 at example.Calculator.divide(Calculator.java:7) at example.Main.main(Main.java:8)
Exceptionクラスのコンストラクタにはメッセージ以外にも、原因を表す例外オブジェクトを設定することもできます。これを使うと原因を表す例外オブジェクトを別の例外オブジェクトでラップすることができます。原因を表す例外オブジェクトはgetCauseメソッドで取り出すことができます。
Part3
独自の例外クラスを作成せずに、JavaのAPIに含まれる標準的な例外クラスを利用することもできます。
計算機クラス
package example; public class Calculator { public int divide(int x, int y) { if (y == 0) { throw new IllegalArgumentException("y is zero"); } return x / y; } }
IllegalArgumentExceptionは不正な引数を表す例外クラスです。IllegalArgumentExceptionはRuntimeExceptionのサブクラスであるため実行時例外に分類されます。
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); try { // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } catch (IllegalArgumentException e) { e.printStackTrace(); // System.out.println(e.getMessage()); } } }
catchする例外クラスをIllegalArgumentExceptionに変更しています。実行時例外の例外処理(try-catch or throws)は任意です。
実行結果
java.lang.IllegalArgumentException: y is zero at example.Calculator.divide(Calculator.java:7) at example.Main.main(Main.java:8)