1. 개요

Java에서 sn eaky throw 개념을 사용하면 메서드 서명에서 명시적으로 정의하지 않고도 검사된 예외를 throw할 수 있습니다. 이렇게 하면 throw 선언을 생략할 수 있으므로 런타임 예외의 특성을 효과적으로 모방할 수 있습니다.

이 기사에서는 몇 가지 코드 예제를 살펴Spring으로써 이것이 실제로 어떻게 수행되는지 볼 것입니다.

2. 몰래 던지기 정보

확인된 예외는 JVM이 아니라 Java의 일부입니다. 바이트코드에서 우리는 제한 없이 어디에서나 예외를 던질 수 있습니다.

Java 8은 throw T허용될 때마다 RuntimeException 으로 유추 된다는 새로운 유형 유추 규칙을 가져왔습니다 . 이것은 도우미 메서드 없이 교활한 던지기를 구현할 수 있는 기능을 제공합니다.

교활한 throw 의 문제 는 결국 예외를 catch하고 싶지만 Java 컴파일러는 특정 예외 유형에 대한 예외 핸들러를 사용하여 몰래 throw된 확인된 예외를 catch하는 것을 허용하지 않는다는 것입니다.

3. 행동에 은밀한 던지기

이미 언급했듯이 컴파일러와 Jave Runtime은 서로 다른 것을 볼 수 있습니다.

public static <E extends Throwable> 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, so it allows the unchecked exception to propagate. The Java Runtime doesn't see any type in the throws as all throws are the same a simple throw e.

This quick test demonstrates the scenario:

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

It's possible to throw a checked exception using bytecode manipulation, or Thread.stop(Throwable), but it's messy and not recommended.

4. Using Lombok Annotations

The @SneakyThrows annotation from Lombok allows you to throw checked exceptions without using the throws declaration. This comes in handy when you need to raise an exception from a method within very restrictive interfaces like Runnable.

Say we throw an exception from within a Runnable; it will only be passed to the Thread's unhandled exception handler.

This code will throw the Exception instance, so there is no need for you to wrap it in a RuntimeException:

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

A drawback with this code is that you cannot catch a checked exception that is not declared; so, it will not compile.

다음은 교활한 예외를 발생시키는 올바른 형식입니다.

@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 에서 사용할 수 있습니다 .

Junit footer banner