[Java] 例外を発生させるthrowsとは?throwとの違いも解説
throws
は、メソッドが例外をスローする可能性があることを宣言するために使用されます。
これにより、メソッドを呼び出す側に例外処理を強制します。
一方、throw
は実際に例外を発生させるために使います。
例えば、throw new Exception("エラーメッセージ")
のように、特定の条件で例外を明示的にスローします。
throws
は宣言、throw
は実行という違いがあります。
- throwsとthrowの役割の違い
- 複数の例外をthrowsで宣言する方法
- カスタム例外を作成して使用する方法
- 条件に応じた例外のスロー方法
- 例外の再スローとラッピングの技術
throwsとは?
Javaにおけるthrows
は、メソッドが特定の例外をスローする可能性があることを宣言するためのキーワードです。
これにより、メソッドを呼び出す側は、例外処理を行うことが求められます。
throws
を使用することで、プログラムの可読性や保守性が向上します。
throwsの基本的な使い方
throws
はメソッドのシグネチャに追加され、メソッドがスローする可能性のある例外を指定します。
以下はその基本的な使い方の例です。
import java.io.IOException;
public class App {
public static void main(String[] args) {
try {
methodThatThrowsException();
} catch (IOException e) {
System.out.println("IOExceptionが発生しました: " + e.getMessage());
}
}
// IOExceptionをスローするメソッド
public static void methodThatThrowsException() throws IOException {
throw new IOException("エラーが発生しました。");
}
}
IOExceptionが発生しました: エラーが発生しました。
throwsで宣言できる例外の種類
throws
で宣言できる例外は、主に以下の2種類に分類されます。
例外の種類 | 説明 |
---|---|
チェック例外 | コンパイル時にチェックされる例外。 |
アンチェック例外 | 実行時に発生する例外で、チェックされない。 |
チェック例外は、IOException
やSQLException
などがあり、メソッドで必ず処理する必要があります。
一方、アンチェック例外は、NullPointerException
やArrayIndexOutOfBoundsException
などがあり、必ずしも処理する必要はありません。
throwsを使う理由
throws
を使用する理由は以下の通りです。
- 明示的な例外処理: メソッドがスローする可能性のある例外を明示的に示すことで、呼び出し元に例外処理を促します。
- コードの可読性向上: 例外の発生を予測しやすくなり、コードの理解が容易になります。
- 保守性の向上: 例外処理を適切に行うことで、プログラムの安定性が向上します。
throwsを使う際の注意点
throws
を使用する際には、以下の点に注意が必要です。
- 例外の種類を正確に指定: スローする可能性のある例外を正確に指定しなければなりません。
- 例外処理の実装: 呼び出し元で適切な例外処理を実装する必要があります。
- メソッドの可読性: 多くの例外を
throws
で宣言すると、メソッドの可読性が低下する可能性があります。
必要な例外のみを宣言することが重要です。
throwsとthrowの違い
Javaにおけるthrows
とthrow
は、例外処理に関連するキーワードですが、それぞれ異なる役割を持っています。
ここでは、その違いについて詳しく解説します。
宣言と実行の違い
throws
はメソッドがスローする可能性のある例外を宣言するために使用されます。
一方、throw
は実際に例外をスローするために使用されます。
以下の表でその違いをまとめます。
キーワード | 説明 | 使用場所 |
---|---|---|
throws | メソッドがスローする例外を宣言する | メソッドのシグネチャ |
throw | 実際に例外をスローする | メソッドの本体内 |
throwsとthrowの使い分け
throws
とthrow
は、以下のように使い分けます。
- throws: メソッドがスローする可能性のある例外を宣言する際に使用します。
これにより、呼び出し元はその例外を処理する必要があります。
- throw: 実際に例外を発生させる際に使用します。
特定の条件が満たされた場合に、例外をスローするために用います。
以下は、throws
とthrow
の使い分けの例です。
import java.io.IOException;
public class App {
public static void main(String[] args) {
try {
methodThatThrowsException();
} catch (IOException e) {
System.out.println("IOExceptionが発生しました: " + e.getMessage());
}
}
// throwsでIOExceptionを宣言
public static void methodThatThrowsException() throws IOException {
// 条件に応じて例外をthrow
if (true) { // 例として常にtrueを返す
throw new IOException("エラーが発生しました。");
}
}
}
throwsとthrowの組み合わせ方
throws
とthrow
は、同じメソッド内で組み合わせて使用することができます。
メソッドがスローする可能性のある例外をthrows
で宣言し、特定の条件に基づいてthrow
で例外を発生させることができます。
以下はその例です。
import java.io.IOException;
public class App {
public static void main(String[] args) {
try {
methodThatMayThrowException(false); // falseを渡す
methodThatMayThrowException(true); // trueを渡す
} catch (IOException e) {
System.out.println("IOExceptionが発生しました: " + e.getMessage());
}
}
// throwsでIOExceptionを宣言
public static void methodThatMayThrowException(boolean shouldThrow) throws IOException {
if (shouldThrow) {
// 条件に応じて例外をthrow
throw new IOException("エラーが発生しました。");
}
System.out.println("正常に処理されました。");
}
}
正常に処理されました。
IOExceptionが発生しました: エラーが発生しました。
このように、throws
とthrow
を組み合わせることで、柔軟な例外処理が可能になります。
throwsの応用例
throws
を使用することで、さまざまな状況において柔軟な例外処理が可能になります。
ここでは、throws
の応用例をいくつか紹介します。
複数の例外をthrowsで宣言する
メソッドが複数の例外をスローする可能性がある場合、throws
を使ってそれらをカンマで区切って宣言することができます。
以下はその例です。
import java.io.IOException;
import java.sql.SQLException;
public class App {
public static void main(String[] args) {
try {
methodThatThrowsMultipleExceptions();
} catch (IOException | SQLException e) {
System.out.println("例外が発生しました: " + e.getMessage());
}
}
// IOExceptionとSQLExceptionをthrowsで宣言
public static void methodThatThrowsMultipleExceptions() throws IOException, SQLException {
// 条件に応じて例外をthrow
if (true) { // 例として常にtrueを返す
throw new IOException("IOエラーが発生しました。");
}
// ここでSQLExceptionをスローすることも可能
// throw new SQLException("SQLエラーが発生しました。");
}
}
例外が発生しました: IOエラーが発生しました。
カスタム例外をthrowsで宣言する
独自の例外クラスを作成し、それをthrows
で宣言することも可能です。
以下はカスタム例外を使用した例です。
// カスタム例外クラス
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
public class App {
public static void main(String[] args) {
try {
methodThatThrowsCustomException();
} catch (CustomException e) {
System.out.println("カスタム例外が発生しました: " + e.getMessage());
}
}
// カスタム例外をthrowsで宣言
public static void methodThatThrowsCustomException() throws CustomException {
throw new CustomException("カスタムエラーが発生しました。");
}
}
カスタム例外が発生しました: カスタムエラーが発生しました。
メソッドチェーンでのthrowsの活用
メソッドチェーンを使用することで、複数のメソッドを連続して呼び出し、例外を一元的に処理することができます。
以下はその例です。
import java.io.IOException;
public class App {
public static void main(String[] args) {
try {
methodChain();
} catch (IOException e) {
System.out.println("IOExceptionが発生しました: " + e.getMessage());
}
}
// メソッドチェーン
public static void methodChain() throws IOException {
methodOne();
}
public static void methodOne() throws IOException {
methodTwo();
}
public static void methodTwo() throws IOException {
throw new IOException("メソッドチェーンでエラーが発生しました。");
}
}
IOExceptionが発生しました: メソッドチェーンでエラーが発生しました。
継承関係におけるthrowsの使い方
継承関係にあるクラスでthrows
を使用する場合、親クラスで宣言した例外を子クラスでオーバーライドする際に、同じ例外またはそのサブクラスを宣言することができます。
以下はその例です。
import java.io.IOException;
class Parent {
// 親クラスでIOExceptionをthrows
public void method() throws IOException {
throw new IOException("親クラスでエラーが発生しました。");
}
}
class Child extends Parent {
// 子クラスで親クラスの例外をオーバーライド
@Override
public void method() throws IOException {
super.method(); // 親クラスのメソッドを呼び出す
}
}
public class App {
public static void main(String[] args) {
Child child = new Child();
try {
child.method();
} catch (IOException e) {
System.out.println("IOExceptionが発生しました: " + e.getMessage());
}
}
}
IOExceptionが発生しました: 親クラスでエラーが発生しました。
このように、throws
はさまざまなシナリオで活用でき、柔軟な例外処理を実現します。
throwの応用例
throw
を使用することで、特定の条件に基づいて例外を発生させたり、例外を再スローしたりすることができます。
ここでは、throw
の応用例をいくつか紹介します。
カスタム例外をthrowでスローする
独自の例外クラスを作成し、throw
を使ってその例外をスローすることができます。
以下はカスタム例外を使用した例です。
// カスタム例外クラス
class MyCustomException extends Exception {
public MyCustomException(String message) {
super(message);
}
}
public class App {
public static void main(String[] args) {
try {
methodThatThrowsCustomException();
} catch (MyCustomException e) {
System.out.println("カスタム例外が発生しました: " + e.getMessage());
}
}
// カスタム例外をthrowでスロー
public static void methodThatThrowsCustomException() throws MyCustomException {
throw new MyCustomException("カスタムエラーが発生しました。");
}
}
カスタム例外が発生しました: カスタムエラーが発生しました。
条件に応じて異なる例外をthrowする
特定の条件に基づいて異なる例外をスローすることも可能です。
以下はその例です。
import java.io.IOException;
import java.sql.SQLException;
public class App {
public static void main(String[] args) {
try {
methodThatThrowsBasedOnCondition(true); // trueを渡す
methodThatThrowsBasedOnCondition(false); // falseを渡す
} catch (IOException e) {
System.out.println("IOExceptionが発生しました: " + e.getMessage());
} catch (SQLException e) {
System.out.println("SQLExceptionが発生しました: " + e.getMessage());
}
}
// 条件に応じて異なる例外をthrow
public static void methodThatThrowsBasedOnCondition(boolean condition) throws IOException, SQLException {
if (condition) {
throw new IOException("IOエラーが発生しました。");
} else {
throw new SQLException("SQLエラーが発生しました。");
}
}
}
このコードを実行すると、最初の呼び出しで以下の出力が得られます。
IOExceptionが発生しました: IOエラーが発生しました。
次の呼び出しでは、以下の出力が得られます。
SQLExceptionが発生しました: SQLエラーが発生しました。
throwを使った例外の再スロー
throw
を使用して、捕捉した例外を再スローすることができます。
これにより、例外を上位の呼び出し元に伝えることができます。
以下はその例です。
import java.io.IOException;
public class App {
public static void main(String[] args) {
try {
methodThatThrowsAndCatchesException();
} catch (IOException e) {
System.out.println("再スローされたIOExceptionが発生しました: " + e.getMessage());
}
}
// 例外を捕捉して再スロー
public static void methodThatThrowsAndCatchesException() throws IOException {
try {
throw new IOException("元のIOエラーが発生しました。");
} catch (IOException e) {
// 例外を再スロー
throw e;
}
}
}
再スローされたIOExceptionが発生しました: 元のIOエラーが発生しました。
throwを使った例外のラッピング
throw
を使用して、捕捉した例外を新しい例外でラッピングすることもできます。
これにより、元の例外情報を保持しつつ、より具体的なエラーメッセージを提供できます。
以下はその例です。
import java.io.IOException;
public class App {
public static void main(String[] args) {
try {
methodThatThrowsWrappedException();
} catch (Exception e) {
System.out.println("ラッピングされた例外が発生しました: " + e.getMessage());
System.out.println("元の例外: " + e.getCause().getMessage());
}
}
// 例外をラッピングしてthrow
public static void methodThatThrowsWrappedException() throws Exception {
try {
throw new IOException("元のIOエラーが発生しました。");
} catch (IOException e) {
// 新しい例外でラッピングしてthrow
throw new Exception("ラッピングされたエラーが発生しました。", e);
}
}
}
ラッピングされた例外が発生しました: ラッピングされたエラーが発生しました。
元の例外: 元のIOエラーが発生しました。
このように、throw
を使用することで、柔軟な例外処理が可能になり、プログラムのエラーハンドリングをより効果的に行うことができます。
よくある質問
まとめ
この記事では、Javaにおけるthrows
とthrow
の使い方やその違い、応用例について詳しく解説しました。
これにより、例外処理の基本的な概念から、実際のプログラムでの活用方法までを理解することができました。
今後は、実際のプロジェクトやコードを書く際に、これらの知識を活かして、より堅牢でエラーに強いプログラムを作成してみてください。