検索

キーワード


【Java】例外クラスの概要や使用実例を解説

  • 公開日:2021-01-26 08:21:20
  • 最終更新日:2021-01-26 08:20:17
【Java】例外クラスの概要や使用実例を解説

こんにちは、駆け出しエンジニアの伊藤です。
東京ITカレッジのJava研修で学んだ内容を復習も兼ねて記事にしたいと思います。
今回は、Javaの例外について、例外の概要や基本的なクラス、代表的な例外の解説をしていきます。
Javaやプログラムについて勉強し始めた方の参考になれば幸いです!
(eclipseを使用して計算を行っています)


関連記事:【Java】例外クラスの制御方法 3種類の基本と使い方を解説

     【Java】例外制御、例外の活用方法入門

     【Java】例外構文 3種類の活用方法解説

     【Java】独自例外を作るには?作成方法を解説




例外の概要

例外とは、プログラムを実行している途中で発生した想定外の異常のことを指します。

例えば、パソコンのメモリが足りなかったり、変数にnullが入ってしまっていたり、指定したファイルが開かなかったり。

ユーザーが使っている際に上記のようなことが起こっては、システムの信頼性や利便性に問題が起きかねません

そこで、Javaでは問題が発生しそうなメソッドに対し、回避策のクラスをそれぞれ用意しています。

それが、皆さん一度は見たことがある「○○Exception」です。

実際にプログラム実行中に例外が発生すると、以下のようなエラーメッセージとして出力されます。

Exception in thread "main" java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 70
 at java.base/java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311)
 at java.base/java.time.temporal.ChronoField.checkValidValue(ChronoField.java:717)
 at java.base/java.time.LocalDate.of(LocalDate.java:269)
 at java.base/java.time.LocalDateTime.of(LocalDateTime.java:361)
 at java.base/java.time.ZonedDateTime.of(ZonedDateTime.java:339)
 at dateTimeCalculation.EqualsSample.main(EqualsSample.java:10)

この中の1行目中央にある「DateTimeException」が、日付/時間の計算時の問題を示すために使用される例外クラスです。

今は上記のエラーメッセージの意味がよく分からない方も、この記事や関連記事を読んでいくとエラーメッセージの意味を理解することができるはずです。

以下では、Exceptionをよく知るために必要なクラスについて解説していきます。



Javaプログラムにおけるエラー

Javaプログラミングのコーディング ~ プログラム実行で発生するエラーを大きく分け3つに分類してみます。


①文法エラー

プログラムの文法(変数名の記述ミス・セミコロン、コンマ、ピリオド等の記述忘れ・スコープ外での呼び出し等)が間違っている場合、コンパイルエラーが起こります。

文法エラーに対しては、コードの修正を行うことで問題が解決できます。

(エクリプスでは、自動文法チェックが有効になっている場合、文法エラーを確認しながら記述することができます)


②実行時エラー

プログラムを実行している途中で、予期していなかった異常が発生し、それ以降のプログラムが処理されず動作がそこで止まってしまいます。

よくある実行時エラーとしては、配列の範囲外要素を指定していた時、0で除算を行った時などです。

文法的なエラーではないため、コンパイルは通りますが想定していた結果が反映されず強制終了となってしまうのです。

実行時エラーに対しては、概要で上げた回避策のクラスを使って対応していきます。


③論理エラー

プログラムは問題なく実行ができ、結果も出力されます。しかし、実行結果が想定した物と違う、ということがあります。

よくある論理エラーとしては、時間の計測結果がおかしい、計算結果が想定していた物と違うなどです。

論理エラーに対しては、違う結果が出た原因を探して修正することが必要です。



①文法エラー、③論理エラーは、開発段階で発見修正が可能です。

しかし、実行時エラーはユーザーの使用環境や使用方法によって発生することが想定されるため、事前に発見修正することは難しいです。

そのため、「もし②実行時エラーが発生したら回避策を実行する」としておくことで強制終了=システムを止めない対策をしておきます。



例外の種類(Throwable, Error, Exception, RuntimeException)

 上記で解説したように、②実行時エラーには事前にシステムを止めないための対策をしておく必要があります。

Javaでは、回避策としての例外クラスが用意されています。

例外クラスは大きく3つに分類されています。

Error・Exception・RuntimeExceptionです。

  

Javaの例外クラスは、下図のような継承型のツリー構造になっています。

Javaの例外クラスの図

Throwableクラスは、例外すべてのスーパークラスです。

例外処理には、Throwableクラスから継承されたサブクラス(Error・Exception・RuntimeExceptionのサブクラスなど)が実際に使われます。


①Errorクラス群

Errorクラスとそのサブクラス群は、重大な問題、異常な状態、実行環境上のトラブルなどを表します。

Error群で見られるクラスとして、VirtualMachineError(JVMが壊れているか、必要なリソースが足りなくなったか)、OutOfMemoryError(メモリ不足)などがあります。

Errorクラス群は、プログラム上では対処の仕様がない回復不可能な例外に当たるため、例外処理の記述は不要です。


②Exceptionクラス群

Exceptionクラスとそのサブクラス群(RuntimeExceptionクラスとそのサブクラス群は除く)は、プログラムを作っているうえで、例外の発生が予想でき対処の必要があるクラスを表します。

Exception群で見られるクラスとして、IOException(入出力処理の失敗)、TimeoutException(タイムアウトエラー)などがあります。

Exceptionクラス群は、回復可能な例外になるので、例外処理を記述する必要があります

必要な例外処理が記述されていない場合は、コンパイルエラーになります。


③RuntimeExceptionクラス群

RuntimeExceptionクラスとそのサブクラス群は、プログラム作成時に例外発生の想定はできるが、対処はしなくても良いクラスを表します。

RuntimeException群で見られるクラスとして、NullPointerException(変数にnullがある)、IndexOutOfBoundsException(配列・文字列などが範囲外)などがあります。

NullPointerExceptionは、例えばすべてのメソッド呼び出しの際にチェックをしていては大変ですし、プログラムも見にくいものになってしまいます。

そのため、RuntimeExceptionクラス群では、回復可能な例外ではありますが、例外処理の記述は必須ではありません。(例外処理を記述することは可能です)



検査例外・非検査例外

プログラム上で対処ができる例外は、上記のExceptionクラスとRuntimeExceptionクラスです。

2つのクラスはそれぞれ、検査例外非検査例外とも呼ばれています。


検査例外・非検査例外とは

検査例外とは、例外処理をプログラムに記述したか、コンパイラが検査する例外のことを言います。

もう一つの、非検査例外とは、例外処理を記述したかをコンパイラが検査しない例外のことを言います。

例外処理は、以下のいずれかの方法で記述する必要があります。

・try-catchでキャッチする

・throws句で例外を宣言する(呼び出し側で try-catch を実装する場合)

(try-catch、throws句は他記事で扱っています。関連記事をご覧ください)


ここまでをまとめると

Error            ‐エラー   ・・・例外処理を記述する必要はない。
Exception        ‐検査例外	・・・例外処理を記述しないとコンパイルエラーが起こる。
RuntimeException ‐非検査例外	・・・例外処理の記述は任意。




代表的な例外(NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException, IOException)

ここでは、プログラムを書いていて遭遇する機会の多い、代表的な例外を簡単に解説します。


NullPointerExceptionクラス

参照型の変数において、nullが入っている状態で参照された場合に発生する例外クラスです。

RuntimeExceptionクラスのサブクラスに当たります。

nullとは、何のデータも含まれない空のデータという意味です。

JavaDocでは、

  null オブジェクトのインスタンスメソッドの呼び出し
  null オブジェクトのフィールドに対するアクセスまたは変更
  null の長さを配列であるかのように取得
  null のスロットを配列であるかのようにアクセスまたは修正
  null を Throwable 値であるかのようにスロー

と記載されています。

それでは、どのような時にNullPointerExceptionが発生するのかをサンプルコードを見ながら解説していきます。


 1 //NullPointerExceptionサンプル
 2 package exception.gaiyou;
 3
 4 public class NullPointerExceptionSample {
 5
 6	   public static void main(String[] args){
 7         int[] array = {1, 2, 3};
 8         array = null;
 9         System.out.println("-----取得結果-----");
10         array[0] = 1;
11     }
12 }


-----取得結果-----
Exception in thread "main" java.lang.NullPointerException
	at exception.gaiyou.NullPointerExceptionSample.main(NullPointerExceptionSample.java:10)


取得結果から分かるように、10行目にエラーが発生しています。

サンプルコードの8行目で、配列変数に nullを代入しています。

nullが代入されたことにより、参照型変数arrayはどこも参照していない状態となっているのです。

JavaDocの記載では、null のスロットを配列であるかのようにアクセスまたは修正 に当たります。

対処としては、故意で参照しない状態にしているのでなければ、例外が発生しないよう変数がきちんと参照できるようにするか、参照する値がnullでないことを事前にチェックするようにプログラムの修正を行います。


関連記事:NullPointerExceptionクラス(JavaDoc)



ArrayIndexOutOfBoundsExceptionクラス

配列の要素外アクセスの例外クラスです。

RuntimeExceptionクラス群に属し、IndexOutOfBoundsExceptionクラスのサブクラスに当たります。

サンプルコードでArrayIndexOutOfBoundsExceptionがどのような時に発生するのか見てみましょう。


 1 //ArrayIndexOutOfBoundsExceptionサンプル
 2 package exception.gaiyou;
 3
 4 public class ArrayIndexOutOfBoundsException {
 5
 6     public static void main(String[] args) {
 7         int[] num = {1, 2, 3};
 8         System.out.println("-----取得結果-----");
 9         System.out.println(num[1]);
10         System.out.println(num[2]);
11         System.out.println(num[3]);
12     }
13 }


-----取得結果-----
2
3
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
	at exception.gaiyou.ArrayIndexOutOfBoundsException.main(ArrayIndexOutOfBoundsException.java:11)

どうしてエラーが発生したか分かるでしょうか?

サンプルコードをよく見ると、11行目の添え字が[3]になっています。

配列の要素数は3つですが、添え字は[0]から始まるので、[0][1][2]になります。

[3]は配列の要素外になるため、ArrayIndexOutOfBoundsExceptionが発生したのです。

配列では、とても多く見る例外クラスです。

しっかりと、要素数と添え字を確認することでこの例外は防ぐことができます。


関連記事:配列の基本

     ArrayIndexOutOfBoundsExceptionクラス(JavaDoc)



ClassCastExceptionクラス

継承関係にないクラス間でキャスト(型変換)しようとした際に発生する例外クラスです。

RuntimeExceptionクラスのサブクラスに当たります。

次のサンプルコードはJavaDocにも掲載されているものです。


 1 //ClassCastExceptionサンプル
 2 package exception.gaiyou;
 3
 4 public class ClassCastException {
 5
 6     public static void main(String[] args) {
 7         Object obj = Integer.valueOf(0);
 8         System.out.println("-----取得結果-----");
 9         System.out.println((String)obj);
10     }
11 }


-----取得結果-----
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
	at exception.gaiyou.ClassCastException.main(ClassCastException.java:9)

7行目でInteger型のオブジェクトを変数 objに代入していますが、9行目で変数 objをString型にキャストをしようとして、失敗しています。

対処としては、型判定の演算子 instanceof を使うことで、キャスト可能な型かチェックすることが可能になります。


※JavaDocで説明されているコードには現在非推奨となっているクラスの使い方が書かれています。

JDK9より new Integer(0); の コンストラクタは非推奨となりましたので、JDK9以降のプログラムでは、サンプルコードのように Integer.valueOf(0);と書く必要があります。


関連記事:ClassCastExceptionクラス(JavaDoc)



IOExceptionクラス

入出力の失敗、または割り込みによって発生する例外クラスです。

ファイルの書き込みや読み取りができない(対象ファイルが存在しない、アクセス権限がないなど)時に見られます。

Exceptionクラスのサブクラスに当たります。


 1 //IOExceptionサンプル
 2 package exception.gaiyou;
 3
 4 import java.io.File;
 5 import java.io.FileWriter;
 6
 7 public class IOException {
 8
 9     public static void main(String[] args) {
10         System.out.println("-----取得結果-----");
11         try {
12             File file = new File("c:\\Sample\\Hello.txt");
13             FileWriter fw = new FileWriter(file);
14             //ファイルの書き込み
15             fw.write("Hello");
16             //ファイルを閉じる
17             fw.close();
18         //例外だった場合のキャッチ部分
19         } catch(java.io.IOException e) {
20             System.out.println(e);
21         }
22     }
23 }


-----取得結果-----

 

取得結果は空白になっていますが、作ったファイルを開くと writeの引数に指定した文字列が書き込まれているはずです。

もし、ファイルの書き込みが何らかの問題で出来なかった場合は、「IOException、ファイル書き込みのエラーが発生しました」と取得結果に出ます。

上記のサンプルプログラムでは、例外処理(try-catch)を記述しないとコンパイルエラーが発生します。

 1 //IOExceptionサンプル(try-catchがない場合に起こるコンパイルエラー)
 2 package exception.gaiyou;
 3
 4 import java.io.File;
 5 import java.io.FileWriter;
 6
 7 public class IOException {
 8
 9     public static void main(String[] args) {
10         System.out.println("-----取得結果-----");
11         File file = new File("c:\\Sample\\Hello.txt");
12         FileWriter fw = new FileWriter(file);
13         //ファイルの書き込み
14         fw.write("Hello");
15         //ファイルを閉じる
16         fw.close();
17     }
18 }


Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	処理されない例外の型 IOException
	処理されない例外の型 IOException
	処理されない例外の型 IOException

	at exception.gaiyou.IOException.main(IOException.java:12)

FileWriterオブジェクトを作るろうとすると、例外が発生します。

IOException例外クラスは、Exceptionクラスのサブクラスに当たるため、検査例外となっています

そのため、try-catch構文がないと上記のようにコンパイルエラーが発生します。

(エクリプスでは、自動文法チェックが有効になっている場合、try-catchを記述しないと文法エラーが発生するため、コンパイルする前にエラーが分かります)


 1 //IOExceptionサンプル(例外発生パターン)
 2 package exception.gaiyou;
 3
 4 import java.io.File;
 5 import java.io.FileWriter;
 6
 7 public class IOException {
 8
 9     public static void main(String[] args) {
10         System.out.println("-----取得結果-----");
11         try {
12             File file = new File("c:\\Sample\\Hello.txt");
13             FileWriter fw = new FileWriter(file);
14             //ファイルの書き込み
15             fw.write("Hello");
16             //ファイルを閉じる
17             fw.close();
18             fw.write("world");
19         //例外だった場合のキャッチ部分
20         } catch(java.io.IOException e) {
21             System.out.println(e);
22         }
23     }
24 }


-----取得結果-----
java.io.IOException: Stream closed

上記のプログラムサンプルでは、18行目に closeメソッドでファイル処理を終了した後に、またファイルに書き込みをしようとしています。

しかし、17行目の closeメソッドでファイル処理のために確保されていたメモリなどが解放されています。

そのため、ファイルに書くことが出来ずIOExceptionエラー(入力の失敗)が発生しています。


関連記事:例外制御(try-catch、try-catch-finally、マルチキャッチ など)

     java.io.Fileクラスの使い方(ファイル一覧の取得、フィルタ)

     IOExceptionクラス(JavaDoc)




まとめ

この記事では、例外の概要や基本クラス、代表的な例外を解説しました。

Javaには、発生した例外に合わせてそれぞれクラスが用意されています。

関連記事で、例外処理の記述方法も解説しているのであわせて覚えておくとプログラムの例外が発生した際、役に立つでしょう。

関連記事:【Java】例外クラスの制御方法 3種類の基本と使い方を解説

     【Java】例外制御、例外の活用方法入門

     【Java】例外構文 3種類の活用方法解説

     【Java】独自例外を作るには?作成方法を解説


【著者】

伊藤

Javaを研修で3か月学んだ、駆け出しのエンジニアです。
現在は、ベンダー資格を取得するため、勉強を日課にできるよう努力中です。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様