JavaのThrowとThrowの違い

Javaのスローとスローの違い

1. 前書き

このチュートリアルでは、Javaのthrowthrowsを見ていきます。 それぞれをいつ使用すべきかを説明します。

次に、それらの基本的な使用法の例をいくつか示します。

2. ThrowおよびThrows

簡単な紹介から始めましょう。 これらのキーワードは、例外処理に関連しています。 Exceptions are raised when the normal of flow of our application is disrupted.

多くの理由があるかもしれません。 ユーザーが間違った入力データを送信する可能性があります。 接続が失われるか、その他の予期しない状況が発生する可能性があります。 適切な例外処理は、これらの不快な瞬間が現れた後でもアプリケーションを動作させ続けるための鍵です。

コードからのWe use throw keyword to explicitly throw an exception。 任意のメソッドまたは静的ブロックが可能です。 この例外はThrowable.のサブクラスである必要があります。また、Throwable自体でもかまいません。 1つのthrowで複数の例外をスローすることはできません。

Throwsキーワードは、メソッド宣言に配置できます。 It denotes which exceptions can be thrown from this method.これらの例外はtry-catchで処理する必要があります。

これらの2つのキーワードは互換性がありません!

3. JavaのThrow

メソッドから例外をスローする基本的な例を見てみましょう。

まず、簡単な電卓を書いて​​いると想像してみてください。 基本的な算術演算の1つは除算です。 そのため、この機能を実装するよう求められました。

public double divide(double a, double b) {
    return a / b;
}

ゼロで除算できないため、既存のコードにいくつかの変更を加える必要があります。 例外を提起するのに良い瞬間のようです。

これをやろう:

public double divide(double a, double b) {
    if (b == 0) {
        throw new ArithmeticException("Divider cannot be equal to zero!");
    }
    return a / b;
}

ご覧のとおり、ニーズに完全に適合するArithmeticExceptionを使用しています。 例外メッセージである単一のStringコンストラクターパラメーターを渡すことができます。

3.1. 良い習慣

We should always prefer the most specific exception.例外的なイベントに最適なクラスを見つける必要があります。 たとえば、IllegalArgumentException. の代わりにNumberFormatException をスローします。不特定のExceptionをスローしないようにする必要があります。

たとえば、java.langパッケージにはIntegerクラスがあります。 ファクトリメソッド宣言の1つを見てみましょう。

public static Integer valueOf(String s) throws NumberFormatException

これは、String. からIntegerインスタンスを作成する静的ファクトリメソッドです。入力Stringが間違っている場合、メソッドはNumberFormatException.をスローします。

A good idea is to define our own, more descriptive exception.Calculator クラスでは、たとえばDivideByZeroException. になります。

サンプルの実装を見てみましょう。

public class DivideByZeroException extends RuntimeException {

    public DivideByZeroException(String message) {
        super(message);
    }
}

3.2. 既存の例外をラップする

既存の例外を自分で定義した例外にラップしたい場合があります。

独自の例外を定義することから始めましょう:

public class DataAcessException extends RuntimeException {

    public DataAcessException(String message, Throwable cause) {
        super(message, cause);
    }
}

コンストラクターは、例外メッセージと原因の2つのパラメーターを取ります。これは、Throwable. の任意のサブクラスである可能性があります。

findAll() functionの偽の実装を書いてみましょう。

public List findAll() throws SQLException {
    throw new SQLException();
}

ここで、SimpleServiceでリポジトリ関数を呼び出します。これにより、SQLException:が発生する可能性があります。

public void wrappingException() {
    try {
        personRepository.findAll();
    } catch (SQLException e) {
        throw new DataAccessException("SQL Exception", e);
    }
}

DataAccessException. と呼ばれる独自の例外にラップされたSQLExceptionを再スローしています。すべてが次のテストによって検証されます。

@Test
void whenSQLExceptionIsThrown_thenShouldBeRethrownWithWrappedException() {
    assertThrows(DataAccessException.class,
      () -> simpleService.wrappingException());
}

これには2つの理由があります。 まず、例外のラッピングを使用します。コードの残りの部分は、システム内のすべての可能な例外について知る必要がないからです。

また、上位レベルのコンポーネントは、下位レベルのコンポーネントについても、それらがスローする例外についても知る必要はありません。

3.3. Javaでのマルチキャッチ

時々、私たちが使用するメソッドは多くの異なる例外を投げることができます。

より広範なtry-catchブロックを見てみましょう。

try {
    tryCatch.execute();
} catch (ConnectionException | SocketException ex) {
    System.out.println("IOException");
} catch (Exception ex) {
    System.out.println("General exception");
}

executeメソッドは、次の3つの例外をスローできます。SocketException, ConnectionException, Exception.最初のcatchブロックは、ConnectionExceptionまたはSocketExceptionをキャッチします。 2番目のcatchブロックは、Exception またはException. の他のサブクラスをキャッチします。we should always catch a more detailed exception first.を覚えておいてください。

catchブロックの順序を入れ替えることができます。 そうすると、すべてがExceptionでキャッチされるため、SocketExceptionConnectionExceptionをキャッチすることはありません。

4. JavaのThrows

メソッド宣言にthrows を追加します。

以前のメソッド宣言の1つを見てみましょう。

public static void execute() throws SocketException, ConnectionException, Exception

The method may throw multiple exceptions.メソッド宣言の最後でコンマで区切られます。 チェックされた例外とチェックされていない例外の両方をthrows. に入れることができます。それらの違いを以下に説明します。

4.1. チェック済みおよび未チェックの例外

A checked exception means that it’s checked at the compile time.この例外を処理する必要があることに注意してください。 それ以外の場合、メソッドはthrowsキーワードを使用して例外を指定する必要があります。

最も一般的なチェック例外は、File. からFileInputStream を作成するときにIOException, FileNotFoundException, ParseException. FileNotFoundException がスローされる可能性があることです。

短い例があります:

File file = new File("not_existing_file.txt");
try {
    FileInputStream stream = new FileInputStream(file);
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

メソッド宣言にthrows を追加することで、try-catchブロックの使用を回避できます。

private static void uncheckedException() throws FileNotFoundException {
    File file = new File("not_existing_file.txt");
    FileInputStream stream = new FileInputStream(file);
}

残念ながら、より高いレベルの関数はこの例外を処理する必要があります。 それ以外の場合は、この例外をthrows keyword.を使用したメソッド宣言に含める必要があります。

反対に、unchecked exceptions aren’t checked at the compile time. 

最も一般的なチェックされていない例外は次のとおりです。ArrayIndexOutOfBoundsException, IllegalArgumentException, NullPointerException. 

Unchecked exceptions are thrown during runtime.次のコードはNullPointerException.をスローします。おそらくこれはJavaで最も一般的な例外の1つです。

null参照でメソッドを呼び出すと、次の例外が発生します。

public void runtimeNullPointerException() {
    String a = null;
    a.length();
}

テストでこの動作を確認しましょう。

@Test
void whenCalled_thenNullPointerExceptionIsThrown() {
    assertThrows(NullPointerException.class,
      () -> simpleService.runtimeNullPointerException());
}

このコードとテストはあまり意味がないことに注意してください。 ランタイム例外を説明するのは学習目的のみです。

Javaでは、ErrorRuntimeExceptionのすべてのサブクラスはチェックされていない例外です。 チェックされた例外は、Throwable classの下にある他のすべてです。

5. 結論

この記事では、2つのJavaキーワードの違いについて説明しました:throwthrows. 基本的な使用法を説明し、グッドプラクティスについて少し話しました次に話しましたチェックされた例外とチェックされていない例外。

いつものように、ソースコードはon our GitHubで見つけることができます。

Javaでの例外処理について詳しく知りたい場合は、記事about Java exceptionsをご覧ください。