1. 概要

Javaでは、sn eaky throw の概念により、メソッドのシグネチャで明示的に定義しなくても、チェックされた例外をスローできます。 これにより、 throws 宣言を省略でき、ランタイム例外の特性を効果的に模倣できます。

この記事では、いくつかのコード例を見て、これが実際にどのように行われるかを見ていきます。

2. 卑劣なスローについて

チェックされた例外はJVMではなくJavaの一部です。バイトコードでは、制限なしにどこからでも例外をスローできます。

Java 8は、 throwsTが許可されるたびにRuntimeExceptionとして推論されることを示す新しい型推論ルールをもたらしました。 これにより、ヘルパーメソッドなしで卑劣なスローを実装することができます。

卑劣なスローの問題は、おそらく最終的に例外をキャッチしたいということですが、Javaコンパイラでは、特定の例外タイプの例外ハンドラを使用して、こっそりスローされたチェック済み例外をキャッチできません。

3. 卑劣なスローの実行

すでに述べたように、コンパイラーとJaveランタイムは異なるものを見ることができます。

public static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
    throw (E) e;
}

private static void throwsSneakyIOException() {
    sneakyThrow(new IOException("sneaky"));
}

コンパイラは、RuntimeExceptionタイプに推測されるスローTの署名を確認するため、チェックされていない例外を伝播できます。 Javaランタイムは、すべてのスローが同じ単純なスローe であるため、スローにタイプを認識しません。

このクイックテストは、シナリオを示しています。

@Test
public void whenCallSneakyMethod_thenThrowSneakyException() {
    try {
        SneakyThrows.throwsSneakyIOException();
    } catch (Exception ex) {
        assertEquals("sneaky", ex.getMessage().toString());
    }
}

バイトコード操作またはThread.stop(Throwable)を使用してチェックされた例外をスローすることは可能ですが、面倒なのでお勧めしません。

4. Lombokアノテーションの使用

Lombokからの@SneakyThrowsアノテーションを使用すると、throws宣言を使用せずにチェック済み例外をスローできます。 これは、次のような非常に制限されたインターフェイス内のメソッドから例外を発生させる必要がある場合に便利です。 実行可能。

Runnable内から例外をスローするとします。 スレッド’sの未処理の例外ハンドラーにのみ渡されます。

このコードはExceptionインスタンスをスローするため、 RuntimeException:でラップする必要はありません。

public class SneakyRunnable implements Runnable {
    @SneakyThrows(InterruptedException.class)
    public void run() {
        throw new InterruptedException();
    }
}

このコードの欠点は、宣言されていないチェック済みの例外をキャッチできないことです。 したがって、コンパイルされません

卑劣な例外をスローするための正しい形式は次のとおりです。

@SneakyThrows
public void run() {
    try {
        throw new InterruptedException();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

そして、これがこの振る舞いのテストです:

@Test
public void whenCallSneakyRunnableMethod_thenThrowException() {
    try {
        new SneakyRunnable().run();
    } catch (Exception e) {
        assertEquals(InterruptedException.class, e.getStackTrace());
    }
}

5. 結論

この記事で見たように、Javaコンパイラーは、チェックされた例外をチェックされていないものとして扱うようにだまされる可能性があります。

いつものように、コードはGitHubから入手できます。