"Schleichende Würfe" in Java

"Sneaky Throws" in Java

1. Überblick

In Java können wir mit dem Konzept von sneaky throwjede aktivierte Ausnahme auslösen, ohne sie explizit in der Methodensignatur zu definieren. Dies ermöglicht das Weglassen der Deklarationthrows, wodurch die Merkmale einer Laufzeitausnahme effektiv imitiert werden.

In diesem Artikel sehen wir uns anhand einiger Codebeispiele an, wie dies in der Praxis geschieht.

2. Über hinterhältige Würfe

Checked exceptions are part of Java, not the JVM. Im Bytecode können wir jede Ausnahme von überall ohne Einschränkungen auslösen.

Java 8 brachte eine neue Typinferenzregel mit, die besagt, dassthrows T alsRuntimeException abgeleitet wird, wann immer dies zulässig ist. Dies gibt die Möglichkeit, hinterhältige Würfe ohne die Hilfsmethode zu implementieren.

Ein Problem mitsneaky throws besteht darin, dass Sie die Ausnahmen wahrscheinlich irgendwann abfangen möchten, der Java-Compiler jedoch nicht zulässt, dass Sie mit dem Ausnahmebehandler für den jeweiligen Ausnahmetyp hinterhältige geprüfte Ausnahmen abfangen.

3. Sneaky Throws in Aktion

Wie bereits erwähnt, können der Compiler und die Jave-Laufzeit verschiedene Dinge sehen:

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

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

The compiler sees the signature with the throws T inferred to a RuntimeException type, sodass sich die ungeprüfte Ausnahme ausbreiten kann. Die Java-Laufzeit sieht keinen Typ in den Würfen, da alle Würfe gleich sind (einfachethrow e.

Dieser Schnelltest demonstriert das Szenario:

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

Es ist möglich, eine aktivierte Ausnahme mithilfe der Bytecode-Manipulation oderThread.stop(Throwable) auszulösen, dies ist jedoch unübersichtlich und wird nicht empfohlen.

4. Verwenden von Lombok-Anmerkungen

Mit der Annotation@SneakyThrows vonLombok können Sie markierte Ausnahmen auslösen, ohne die Deklarationthrowszu verwenden. Dies ist praktisch, wenn Sie eine Ausnahme von einer Methode innerhalb sehr restriktiver Schnittstellen wieRunnable. auslösen müssen

Angenommen, wir lösen eine Ausnahme innerhalb vonRunnable aus. Es wird nur an den nicht behandelten Ausnahmebehandler vonThread’sübergeben.

Dieser Code löst die Instanz vonExceptionaus, sodass Sie sie nicht inRuntimeException: einschließen müssen

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

Ein Nachteil dieses Codes ist, dass Sie keine aktivierte Ausnahme abfangen können, die nicht deklariert ist. so, it will not compile.

Hier ist die richtige Form, um eine hinterhältige Ausnahme auszulösen:

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

Und hier ist der Test für dieses Verhalten:

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

5. Fazit

Wie wir in diesem Artikel gesehen haben, kann der Java-Compiler dazu verleitet werden, geprüfte Ausnahmen als nicht markiert zu behandeln.

Wie immer ist der Codeover on GitHub verfügbar.