初心者のJavaプログラミング

プログラミングガチ初心者がIT業界を目指して頑張ります。

【第25回】初心者のJavaプログラミング【例外処理(try, catch)】

こんにちは。
最近鼻の調子が悪いです。
風邪か花粉か。イネ科のかもがや?っていう河原に生えているやつの花粉症なんですよね。だから、春と秋だと秋のほうがひどい傾向がるんですよねー。
あと、ほこりアレルギーっぽいので掃除すると具合悪くなりますw

ってことで今回は例外処理です。

例外とは

良く分からないので、とりあえず例外を出してみます。
0除算が手っ取り早いです。
整数を0で割ってしまってはだめなのです!

class ExceptionZeroJosan {
	public static void main(String[] args) {
		int a = 5;
		int b = 0;
		int c = a / b;
		System.out.println(c);
	}
}

文法的に正しいのでコンパイルは通りますが、
int c = a / b;
の行で実行時にエラーが出ます。

Exception in thread "main" java.lang.ArithmeticException: / by zero
といったエラーが表示されます。
ArithmeticExceptionクラスの例外オブジェクトが生成されていることを意味しています。

このように例外とは、プログラムの実行中に発生した問題を通知するために、実行時に生成されるオブジェクトのことです。

Javaではこの例外を、前もって準備しておいた処理ルーチンで処理することが出来ます。

例外処理の書き方

class ExceptionZeroJosan {
	public static void main(String[] args) {
		int a = 5;
		int b = 0;
		try { //< 例外が発生する恐れのある処理を書く
			int c = a / b;
			System.out.println(c);
		}
		catch(ArithmeticException ex) { //< 例外発生した時の処理
			System.out.println("0で割っちゃだめだよー");
		}
		finally { //< 必ず実行される
			System.out.println("終わり");
		}
	}
}

コンパイルして実行してみると、
"0で割っちゃだめだよー"
"終わり"
が表示されたと思います。

tryの中に例外が発生する恐れのあるコードを書いていきます。
0除算は例外が発生しそうというかします。
予定通り例外が発生して、ArithmeticExceptionクラスのオブジェクトが生成されました。
その例外がcatch(ArithmeticException ex)のexに引数として受け取っています。
その例外に対しての処理をcatchブロックの中に書いていきます。
catchは例外をキャッチ!って感じです。
そんで、finallyブロックですが、これは必ず実行されます。
tryで例外が発生しなかった場合でも、例外が発生した場合でも実行されるということです。
try文にretrunステートメントがあったとしても、すぐに関数を抜けずfinallyブロックの処理をします。ここがちょっと紛らわしいです。

例外オブジェクトに対応するcatchブロックがなかった場合

例外にも色々種類があって、

  • 0で除算した時等に発生する例外
  • 配列の範囲外を参照してしまった場合の例外

等です。
もし上の例で、配列の範囲外を参照してしまった場合の例外のオブジェクトをキャッチするようなコードを書いていた場合、せっかく例外をキャッチしようとしてもできません。

catch(ArithmeticException ex)となっている部分を
catch(ArrayIndexOutOfBoundsException ex) に変更してみて下さい。
例外はキャッチされずに、finallyブロックだけが実行されて終わります。

まあ、気をつけましょうってことです!w

(キャッチできなかった場合、呼び出し元のメソッド内のtryブロックのcatchブロックに検索しにいきます。見つかった段階で検索を終了して処理をします。)
ちょっとややこしいですが例文を一つ。

class ExceptionZeroJosan {
	public static void testA() {
		try {
			testB(); //< 2
		}
		catch(ArithmeticException ex) { //< 7 呼び出し元まで探しにくる。
			System.out.println("testAメソッド内でキャッチしたよ!"); //< 8 例外キャッチ
		}
		finally { //< 9 必ず実行されます。呼び出し元に戻る。
			System.out.println("ふはは!");
		}
	}

	public static void testB() { //< 3
		int x = 5;
		int y = 0;
		try {
			int z = x / y; //< 4 (例外発生!)
			System.out.println("あああ");
		}
		catch(ArrayIndexOutOfBoundsException ex) { //< 5 (クラスが違うのでキャッチできず)
			System.out.println("testBメソッド内でキャッチしたよ");
		}
		finally { //< 6 必ず実行されます。呼び出し元に戻ります。	
			System.out.println("ぐぬぬ...");
		}
	}

	public static void main(String[] args) {
		try {
			testA(); //< 1
		}
		catch(NumberFormatException ex) {
			System.out.println("0で割っちゃだめだよー");
		}
		finally { //< 10 必ず実行されます
			System.out.println("終わり");
		}
	}
}

処理される順番を書いておいたので追ってみて下さい。


ちなみにですが、全ての例外のスーパークラスであるExceptionクラスとして例外オブジェクトを引数で受け取れば例外のキャッチが出来ます。
catch(Exception ex)としてみて下さい。
catch(ArithmeticException ex)としたときと同じ実行結果になるはずです。




次はthrowステートメントについて書こうとおもったのですが、
あまり良く分かっていないことにたった今気付き、絶望していますw
もうちょっと勉強して出直してからきますw

それでは今日はコレくらいで。
皆さん、暑くなったり涼しくなったりしているので体調崩さないように。
ではでは。