31. エラーハンドリング

エラーハンドリングの種類

エラーハンドリング(例外処理)をするとき、以下の3つの構文があります。

  • try-catch
  • throw
  • throws

エラーハンドリングの意味

プログラム実行中にエラーが発生すると、通常のプログラムは異常終了してしまいます。プログラムを継続的に実行するには、例外処理で回避しなければいけません。

try-catch

try-catchの基本構文

try-catch文は、tryブロックcatchブロックで構成されます。tryブロックには例外が発生する可能性のある処理を、catchブロックに例外が発生したときの処理を記述します。また、catchの引数には例外クラスを指定して、さまざまな例外の種類に対応できます。

try {
    //例外発生の可能性がある処理
} catch (例外クラス インスタンス) {
    //例外処理が発生したときの処理
}

複数の例外

「try-catch」文は複数の例外クラスに対応しているので、catchブロックを複数記述できます。

try {
    //例外発生の可能性がある処理
} catch (例外クラス1 インスタンス1) {
    // 対策処理1
} catch (例外クラス2 インスタンス2) {
    // 対策処理2
} finally {
    // 例外に関わらず必ず実行する処理
}

finally

finallyは、try-catch文で例外が発生しなくても必ず処理されるブロックです。例外に関わらず必ず実行したい処理がある場合に、記述するとよいでしょう。

try {
    //例外発生の可能性がある処理
} catch (例外クラス1 インスタンス1) {
    // 対策処理1
} catch (例外クラス2 インスタンス2) {
    // 対策処理2
} finally {
    // 例外に関わらず必ず実行する処理
}

ファイル読み込み(try-catch)

ファイル構成

./
└── data/
  └── sample.txt
└── src/
  └── sample/
    └── ExceptionSample.java

テキストファイルの準備

「data/sample.txt」にテキストを記述しておきます。

sample.txt
Hello
こんにちは

ファイル読み込み

「FileReader」は、Javaでファイルを読み込むクラスです。

FileReader reader = new FileReader(ファイルパス);

loadFile() メソッドで、指定されたパスからファイルを読み込んでみます。

ExceptionSample.java
	public static void loadFile(String path) {
		FileReader reader = new FileReader(path);
	}

コンパイルエラー

「FileReader」のインスタンスでファイルが読み込もうとすると、コンパイルエラーになります。これはファイルが読み込まれない可能性があるからです。

try-catchで回避

「FileReader」で処理するには、「try-catch」文で例外処理が必要です。Eclipseでは「try/catchで囲む」で「try-catch」文を自動挿入できます。

「try-catch」文が作成されたら、通常処理と例外処理を記述しましょう。

ExceptionSample.java
	public static void loadFile(String path) {
		try {
			FileReader reader = new FileReader(path);
			System.out.println("ファイルを読み込みました");
		} catch (FileNotFoundException e) {
			System.out.println("ファイルが存在しませんでした");
		}
	}

動作確認

loadFile() にファイルパスを指定して、ファイルが読み込めるか確認してみましょう。

ExceptionSample.java
	public static void main(String[] args) {
		loadFile("./data/sample.txt");
	}

データ読み込み

「FileReader」クラスの read() メソッドで文字を1文字ずつ読み込めます。

int data = read();

データ読み込み

「BufferedReader」は、「FileReader」で指定したファイルから、文字を行単位で読み込むことができます。

BufferedReader buffer = new BufferedReader(reader);

行単位で読み込み

ファイルのデータを、while文で行単位で読み込みます。

BufferedReader buffer = new BufferedReader(reader);
String line;
while ((line = buffer.readLine()) != null) {
    System.out.println(line);
}
buffer.close();
reader.close();

コンパイルエラー

readLine() でデータを読み込もうとすると、コンパイルエラーになります。

catchの追加

これを回避するには「IOException」クラスで catch する必要があります。 Eclipseでは「周囲の try に catch 文節を追加」で「catch」文を自動挿入します。

例外クラス「IOException」の catchブロックが追加されました。

	public static void loadFile(String path) {
		try {
			FileReader reader = new FileReader(path);
			System.out.println("ファイルを読み込みました");

			BufferedReader buffer = new BufferedReader(reader);
			String line;
			while ((line = buffer.readLine()) != null) {
				System.out.println(line);
			}
            buffer.close();
            reader.close();
		} catch (FileNotFoundException e) {
			System.out.println("ファイルが存在しませんでした");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

finallyの追加

finallyブロックを追加して、共通処理を記述します。

	public static void loadFile(String path) {
		try {
			...
		} catch (FileNotFoundException e) {
			System.out.println("ファイルが存在しませんでした");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			System.out.println("ファイル読み込み処理を終了します");
		}
	}

動作確認

プログラムを実行して「data/sample.txt」ファイルのテキスト内容が表示できるか確認してみましょう。

結果(ファイルがある場合)
Hello
こんにちは
ファイル読み込み処理を終了します。
結果(ファイルがない場合)
ファイルが存在しませんでした
ファイル読み込み処理を終了します

throws

throwsとは

throwsは例外が発生したときに、呼び出し元に例外処理を投げる方法です。

	public メソッド() throws 例外 {
		//例外の可能性のある処理
	}

ファイル読み込み(throws)

loadFile2() メソッドで同じようにファイル読み込み処理を作成します。

	public static void loadFile2(String path)  {
		FileReader reader = new FileReader(path);
		System.out.println("ファイルを読み込みました");

		BufferedReader buffer = new BufferedReader(reader);
		String line;
		while ((line = buffer.readLine()) != null) {
			System.out.println(line);
		}
        buffer.close();
        reader.close();
	}

throwsの追加

Eclipseで「スロー宣言の追加」を選択します。

throwsに「IOException」が追加されました。

	public static void loadFile2(String path) throws IOException {
		FileReader reader = new FileReader(path);
		System.out.println("ファイルを読み込みました");

		BufferedReader buffer = new BufferedReader(reader);
		String line;
		while ((line = buffer.readLine()) != null) {
			System.out.println(line);
		}
        buffer.close();
        reader.close();
	}

呼び出し元で「try-catch」

コンパイルエラー

loadFile2() を実行するとコンパイルエラーになります。

	public static void main(String[] args) {
		...

		loadFile2("./data/sample.txt");
	}

try-catchの追加

呼び出し元で「try-catch」文を追加します。

「try-catch」文が作成されたら、通常処理と例外処理を記述しましょう。

	public static void main(String[] args) {
		...

		try {
			loadFile2("./data/sample.txt");
		} catch (IOException e) {
			System.out.println("ファイルエラー");
		}
	}

動作確認

プログラムを実行して動作確認してみましょう。

結果
Hello
こんにちは

throw

throwは、意図的に例外を発生させて、エラー処理します。例えば値が想定と違う場合、意図的に例外を発生させ、エラーメッセージを返すことができます。

throw new Exceptionクラス(値);

throwの例

「count」がマイナスの数値と判別したら、「IllegalArgumentException」を発生させて、catchで処理します。

	public static void main(String[] args) {
		float average = 0;
		...

		average = calculateAverage(100, -1);
		System.out.println(average);
	}

	public static float calculateAverage(int score, int count) {
		try {
			if (count < 0) {
				throw new IllegalArgumentException("個数がマイナスです。");
			}
		} catch (IllegalArgumentException e) {
			System.out.println(e.getMessage());
		}
		...
	}

結果

例外が catchできました。

個数がマイナスです。

演習

問題1

「IOException」の例外処理をする「try-catch」文で正しいのはどれですか?

1)try { } catch { }

2)try (IOException e) { } catch { }

3)try { } catch (IOException e) { }

4)try (IOException e) { } catch (IOException e) { }

問題2

「IOException」の例外処理をする「throws」文で正しいのはどれですか?

1)public check() throws IOException { }

2)public check(IOException e) throws { }

3)public check() throws IOException(e) { }

4)public check(throws IOException) { }

問題3

Nullを強制的に発生させる処理で、正しいのはどれですか?

1)NullPointerException();

2)throw NullPointerException();

3)new NullPointerException();

4)throw new NullPointerException();