前回の記事で、コンパイルエラーと実行時エラーというものを書いていた。
【備忘録】Javaにおける「コンパイルエラー」と「実行時エラー」 | Shino’s Mind Archive
そのコンパイルエラーはいいのだが、実行時エラーの記載が足りていなかったので、今回でそれを補足する。
…とはいったものの、ちょっとまだ自分の中に落とし込めていない。
考えを整理しつつ書いていくので、誤りがあったら指摘していただければ幸いだ。
用語の整理
まずはここからやっていこう。
ここから先、エラーと例外という単語がたびたび出てくる。
先に、これらの定義から確認しよう。
まず、エラーは2種類の意味が含まれているように思う。
一つは広義のエラーで、実行時エラーと言った場合のエラーがこれだ。
これは、狭義のエラーと、例外をまとめた呼び方。
その狭義のエラーとは、想定されない異常事態、と認識している。
そしてもう一つ。例外とは、想定された異常事態、といったところだろうか。
想定された、ということは、それなりの対処が可能だ。
それが、例外処理…例外発生時に行う処理だと捉えている。
今回、ここから解説する内容は、実行時エラーにはどんなものがあるのかだけに抑えておく。
例外処理は、次回まとめて解説していこう。
実行時エラーの分類
実行時エラーには、狭義のエラーと例外があると書いた。
この例外にも2種類あり、まとめると以下のようになる。
- Error : 狭義のエラー
- 例外
- RuntimeException : 非チェック例外
- Exception : チェック例外
詳細を見ていこう。
Error : 狭義のエラー
これは、Javaの仕組みとして問題が発生した場合に起こるものだ。
これはそもそも発生させてはならず、起きたからどうする、といったことは考えない。
具体的なものを二つほどあげておこう。
まずは、OutOfMemoryErrorというもの。
そもそも、Javaを動かしている時は、変数などの情報を一時的な領域に保持している。
この一時的な領域が不足した場合に、これが発生する。
そして、もう一つはStackOverflowErrorというもの。
これも領域不足によるものだが、上のものとはまた別の領域になる。
Javaの内部動作の話になってしまうが、処理の中でメソッドを呼ぶ処理があったとしよう。
その時、そこで処理していたものを一度保存しておき、メソッドの処理に移る。
メソッドの処理が終わると、保存していたデータを取り出し、元の処理に戻る。
この、一度保存しておく領域(仕組み)のことをStackと呼ぶ。
で、あまりにもメソッドを呼び出しすぎて、このStackが足りなくなると、Stackがあふれる、つまりStackOverflowErrorが発生する。
どちらも、プログラム実行に必要な領域がなくなったということで、それ以上処理を続けることができない。
だから、起きたらどうするかではなく、起こさないためにどうするか考える必要があるのだ。
RuntimeException : 非チェック例外
これは、プログラムによる例外処理が強制されていない例外だ。
強制されていない、ということはもちろん書くこともできる。
つまり、例外処理が書かれているかのチェックを行わない、非チェック例外と言う。
ただし、こちらの場合は、そもそもこれが起きないように変数チェックなどを行うべきだろう。
起きないようにするという考え方はエラーと同じだが、プログラム側で対処可能という点では異なる。
この例外が発生するような状況であれば、代わりに別の処理を行ったり、そもそもその処理を行わないようにする。
これはその時の状況によって異なるので、最終的にどうなっていればいいかを考えておこう。
具体的な例としては、前回挙げた二つの例外だ。
そのうち、配列の方で対処をしてみよう。
まず、例外が発生していたソースコードを再掲しておく。
public class SampleClass {
public static void main (String[] args) {
errorTest(0);
errorTest(1);
errorTest(2);
errorTest(3);
errorTest(4);
errorTest(5);
}
static void errorTest (int index) {
int[] array = new int[5];
array[index] = 10;
}
}
これを実行すると、8行目の関数呼び出しにて、13行目の処理を行ったタイミングで例外が発生していた。
原因は、配列の範囲外でアクセスしようとしていたこと。
では、これに対応してみよう。
やることは簡単。関数の中で、配列の範囲内だったら10を代入する、という条件を付け加える。
付け加えたものが以下だ。
public class SampleClass {
public static void main (String[] args) {
errorTest(0);
errorTest(1);
errorTest(2);
errorTest(3);
errorTest(4);
errorTest(5);
}
static void errorTest (int index) {
int[] array = new int[5];
if(index >= 0 && index < 5) {
array[index] = 10;
}
}
}
こうすることで、引数のindexが0から4の場合でのみ配列への代入が発生する。
つまり、範囲外のアクセスになることがなくなった。
Exception : チェック例外
こちらは、プログラムによる例外処理が強制された例外になる。
つまり、これに該当する例外が発生する可能性のある場合は、それが発生した際の処理を書かなければいけない。
書かないと、そもそもコンパイルの段階で弾かれる。
コンパイルによって例外処理が書かれているかチェックする、よってチェック例外。
この例としては、ファイルを読み込む場合で考えてみよう。
ファイルを読み込む際には、二つの例外が発生する場合がある。
そもそもファイルを読み込む際の処理は、以下のような流れになる。
- ファイルを開く
- 開いたファイルからデータを読み込む
このそれぞれで、例外が発生する場合があるのだ。
一つは、FileNotFoundExceptionというもの。
ファイルを開こうとした際に、そもそもファイルが存在しない場合に発生する例外だ。
もう一つは、IOException。
こちらは、ファイルは開けたものの、その中身にアクセスできなかった場合に発生する。
つまり、ファイルを読み込む際には、開けなかった場合と、データを読み込めなかった場合の二つの例外処理を書く必要があるのだ。
その具体的な例外処理は、次回説明していこう。
まとめ:実行時エラー
一応、今の理解で書いてみた。最後にもう一度まとめてみよう。
プログラムを実行した際に発生する可能性のある狭義のエラー、例外をまとめて実行時エラーと呼ぶ。
狭義のエラーは想定されない異常事態でプログラム側では対処できず、そもそも発生させないようにしなければならない。
例外は想定された異常事態でプログラム側で対処が可能。
この、例外が発生した場合にどう対応するか、というのが例外処理。
例外の中でも、RuntimeExceptionは例外処理という形で対処を書く必要がないもの。
これは、対処としては狭義のエラーと同じくそもそも発生させないようにという方針。
もう一つ、Exceptionは例外処理の記述が強制されたもの。
こちらは、例外が発生したらどうするのかをしっかり書いていこう。
次回は、何度も単語が出てきた例外処理についてまとめていく。
今回のように不足があったらまた追加していこう。
前回の冒頭にも書いたがかなり苦手なところで再勉強中なので、許してほしい…
更新情報はTwitter、Facebookにて告知している。
どちらも、ページ下部の各アイコンから確認できるので、よかったら覗いていってほしい。
それでは。
コメント