当サイトは、アフィリエイト広告を利用しています

javaの例外処理~throwとthrowsについて~

作成日:2022月03月23日
更新日:2023年11月30日

javaの例外処理における「throw」と「throws」について 基本的なところをまとておく

javaの例外処理については下記の書籍が参考になります

例外処理とは?

javaには検査例外と実行時例外がある。
例外処理はこのうちを検査例外が発生したときの処理をコーディングする。

例外が発生する可能性があるメソッドではそのメソッドにおいて

  • 例外を捕捉するか、
  • 呼び出し元メソッドに例外を投げる(任せる)

か決めて対応をしておく必要がある。 実装としてはを

  • try~catch
  • throws を書いていくことになる。

throwとは?

意図的に例外を発生させる機能。
例外的状況が発生したどうかはJVMが監視していて、
JVMが例外的状況を検知すると処理をcatchブロックに移す。
この例外を監視しているJVMに対して、意図的に「Exception」が発生したと通知するのが
throw命令。 例外を発生させたい場所で実行する

throwSample
private static void doError() {
try {
throw new Exception("error");
} catch(Exception e) {
e.printStackTrace();
}
}
}

throwsとは?

プログラムに例外が生じた際に、呼び出し元に例外処理を投げる機能
例外をthrowsするメソッドに記述することで例外が発生した場合
処理が呼出し元のcatch句に移る。
※throwsはネストさせることもできるが最上位のところでは
try~catchを書いて、例外を捕捉する必要がある。

throwsSample
import java.util.*;
public class Main {
// 呼出し元
public static void main(String[] args) {
try {
doError();
} catch (Exception e) {
e.printStackTrace();
}
}
// 実行側
private static void doError() throws Exception {
throw new Exception("error!!");
}
}

Java throwsとは|throwsとthrowの違いも紹介

実装サンプル

例外処理のパターンをいくつか実装してみる

メソッド内で例外を捕捉する

呼出し元ではなく実行メソッド内で例外を捕捉するパターン。

実行メソッド内でtry~catchを書いて捕捉する

呼出し元

  • 例外は実行側で処理するため呼出し元はtry~catchは不要。

実行側

  • 例外を捕捉、処理する。
実行メソッド内で例外を捕捉
import java.util.*;
public class Main {
// 呼出し元
public static void main(String[] args) {
doError();
}
// 実行メソッド
private static void doError() {
try {
//例外を発生させる
throw new Exception("error!!");
} catch(Exception e) {
// 例外を捕捉
//ログ出力
e.printStackTrace();
}
}
}

メソッド呼出し元に例外を投げる

実行メソッドではなく呼出し元で例外を捕捉するパターン。

throwsで投げる

呼出し元

  • throws付きの実行メソッドを呼んでいるためtry~catchが必要。
  • catch句で実行メソッドの例外を受け取って処理する
  • 例外が発生した場合、catch句に処理が移るため、try句のdoErrorより下の処理は実行されない。

実行側

  • 例外を呼出し元に投げる(実行側では処理しない)
例外を呼出し元に投げる
import java.util.*;
public class Main {
// 呼出し元
public static void main(String[] args) {
try {
doError();
} catch (Exception e) {
//実行側の例外を捕捉して処理する
e.printStackTrace();
}
}
// 実行側
private static void doError() throws Exception {
//例外を発生させる
//メソッドにthrowsがあるため例外を呼び出し元に投げる
throw new Exception("error!!");
}
}

try~catchで投げる(NullPointerException)

throwsではなくtry~catchでも呼び出し元に投げることができる
NullPointerExceptionが発生するパターンを実装してみる

呼出し元

  • 呼出し元でも例外捕捉するためtry~catchが必要。
  • catch句で実行メソッドの例外を受け取って処理する
  • 例外が発生した場合、catch句に処理が移るため、try句のdoErrorより下の処理は実行されない。

実行側

  • throwsでなくtry~catchを使う
  • try句で発生したエラーをcatch句で受け取る。
  • catch句で発生した例外は呼出し元のcatch句で捕捉する
例外を呼出し元に投げる(try-catch)
import java.util.*;
public class Main {
//呼出し元
public static void main(String[] args) {
try {
doError();
System.out.print("処理は継続する");
} catch (Exception e) {
e.printStackTrace();
}
}
//実行側
private static void doError() {
try {
 //例外を発生させる
throw new NullPointerException ("ヌルぽ");
} catch(Exception e) {
 //try句で発生したエラーをそのまま呼出し元に投げる
throw e;
}
}
}

Exceptionを発生させる場合

Exceptionを発生させる場合はthrowsが必要

例外を呼出し元に投げる(try-catch)
import java.util.*;
public class Main {
//呼出し元
public static void main(String[] args) {
try {
doError();
System.out.print("処理は継続する");
} catch (Exception e) {
e.printStackTrace();
}
}
//実行側
private static void doError() throws Exception{
try {
//例外を発生させる
throw new Exception ("エクセプション");
} catch(Exception e) {
//try句で発生したエラーをそのまま呼出し元に投げる
throw e;
}
}
}

参考

Java throw 作成した例外を投げる/上位に投げる

例外処理がcatchされなかった場合は?

例外処理がcatch句で適切にcatchされなかった場合はRuntimeErrorとなり
強制終了する。

実行エラーになるケース

実行エラー
import java.util.*;
public class Main {
//呼出し元
public static void main(String[] args) {
try {
doError();
//発生させた例外でない例外のみcatch
} catch (IndexOutOfBoundsException e) {
System.out.print(e.getMessage());
e.printStackTrace();
}
}
//実行側
private static void doError(){
try {
//例外を発生させる
throw new NullPointerException ("ヌルぽ");
} catch(Exception e) {
//try句で発生したエラーをそのまま呼出し元に投げる
throw e;
}
}
}

このような場合はNullPointerExceptionがcatchできないため
強制終了する。下記のように書いたりしてcatch漏れがないようにする。

対応サンプル

実行エラー
//呼出し元
public static void main(String[] args) {
try {
doError();
//発生させた例外でない例外のみcatch
} catch (IndexOutOfBoundsException e) {
System.out.print(e.getMessage());
e.printStackTrace();
} catch (NullPointerException e) {
System.out.print(e.getMessage());
e.printStackTrace();
}
}

または

実行エラー
//呼出し元
public static void main(String[] args) {
try {
doError();
//発生させた例外でない例外のみcatch
} catch (IndexOutOfBoundsException | NullPointerException e) {
System.out.print(e.getMessage());
e.printStackTrace();
}
}

握りつぶしについて

例外が発生したことをなかったことにしてハンドリングしないことを例外を握りつぶすという。
例外処理はcatch処理をした場所で伝播が止まってしまう性質のため発生する。
※処理した例外はそこで処理したのでもう上へは連携されないこと
適切に処理しないと エラーを握りつぶしてしまうケースがある。

一見ちゃんと終わったかのように見えるパターン

実行メソッドのcatch句での例外処理はログ出力しかしていない。
呼出し元は実行メソッドのcatch句の処理が完了した後、順位実行される。

握りつぶしパターン1
import java.util.*;
public class Main {
// 呼出し元
public static void main(String[] args) {
doError();
System.out.print("例外あるけど完了した");
}
// 実行メソッド
private static void doError() {
try {
//例外を発生させる
throw new Exception("error!!");
} catch(Exception e) {
// 例外を捕捉
//ログ出力
e.printStackTrace();
}
}
}
// 実行結果
// 例外あるけど完了した

実際ログを見るとエラーは発生しているがユーザーはログなど
基本見ないので例外は発生していることに気づかないため
例外がつぶされていることになる。
※まだログ出力処理があればいいがないと完全に闇に葬られることになる...

log
java.lang.Exception: error!!
at Main.doError(Main.java:14)
at Main.main(Main.java:6)

例外原因が分からなくなるパターン

catch句で例外が発生した場合や、正しく処理しなかった場合に
例外原因が握りつぶされてなくなってしまうパターン。

握りつぶしパターン2
import java.util.*;
public class Main {
/**
* 例外をcatchしStackTraceを表示するメソッド
* @param args
*/
public static void main(String[] args) {
try {
doMethod();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* catch句で例外をthrowするメソッド
* @throws Exception
*/
private static void doMethod() throws Exception {
try {
throw new Exception("throw in try");
} catch(Exception e) {
 //catch内で例外を発生させる
throw new Exception("throw in catch");
}
}
}

実行すると

log
java.lang.Exception: throw in catch
at Main.doMethod(Main.java:24)
at Main.main(Main.java:11)

tyr内のerror情報が握りつぶされてなくなっている。

### 対応

addSuppressed

addSuppressedを使って例外を追加することができる

addSuppressed
import java.util.*;
public class Main {
/**
* 例外をcatchしStackTraceを表示するメソッド
* @param args
*/
public static void main(String[] args) {
try {
doMethod();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* catch句で例外をthrowするメソッド
* @throws Exception
*/
private static void doMethod() throws Exception {
try {
throw new Exception("throw in try");
} catch(Exception expInTry) {
Exception expInCatch = new Exception("throw in catch");
expInCatch.addSuppressed(expInTry);
throw expInCatch;
}
}
}

実行すると

log
java.lang.Exception: throw in catch
at Main.doMethod(Main.java:24)
at Main.main(Main.java:11)
Suppressed: java.lang.Exception: throw in try
at Main.doMethod(Main.java:22)
... 1 more

try内のerror情報もlogに出力できる

参考

【Java】catch句で例外が発生した場合の書き方【addSuppressed】

新着記事

タグ別一覧
top