Javaでの「卑劣な投げ」

1概要

Javaでは、sn __eaky throw という概念により、メソッドシグネチャで明示的に定義しなくても、チェック済み例外をスローできます。これにより、 throws__宣言を省略して、実行時例外の特性を効果的に模倣することができます。

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

2卑劣な投球について

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

Java 8では、 throws T が許可されている場合は常に RuntimeException として推論されることを示す新しい型推論規則が導入されました。これにより、ヘルパーメソッドなしで卑劣なスローを実装することができます。

sneaky throws の問題は、おそらく最終的には例外をキャッチしたいということですが、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 type ** に推論された throws T のシグニチャを見ているので、チェックされていない例外を伝播させることができます。すべての投球が同じ単純な__投球であるので、Javaランタイムは投球のどんなタイプも見ません。

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

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

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

4ロンボク注釈の使用

Lombok @ SneakyThrows アノテーションを使用すると、 throws 宣言を使用せずにチェック済み例外をスローできます。 Runnable. のような非常に制限の厳しいインタフェース内のメソッドから例外を発生させる必要があるとき、これは役に立ちます。

Runnable 内から例外をスローしたとしましょう。それは__スレッドの未処理の例外ハンドラにのみ渡されます。

このコードは 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コンパイラーは、チェック済み例外をチェックなしとして扱うようにだまされる可能性があります。

いつものようにコードが利用可能ですhttps://github.com/eugenp/tutorials/tree/master/core-java-lang[GitHubでオーバー]