Runnable ) 을 구현하는 클래스의 run () 에서 호출하는 메서드 는 예외를 throw하도록 설계되었습니다.
그러나 Java 컴파일러는 그렇게 할 수 없으며 try / catch로 둘러싸라고 제안합니다.
문제는 그것을 try / catch로 둘러 싸서 특정 run ()을 쓸모 없게 만든다는 것 입니다 . 내가 할 그 예외를 throw합니다.
내가 지정하는 경우 throws
에 대한 ) (실행 자체를, 컴파일러는 불평 Exception is not compatible with throws clause in Runnable.run()
.
보통 나는 run () 이 예외를 던지 도록하지 않아도 괜찮습니다 . 하지만 그 기능이 있어야하는 독특한 상황이 있습니다.
이 제한을 어떻게 해결합니까?
답변
당신이 구현하는 클래스를 전달하려는 경우 Runnable
에 Thread
프레임 워크, 당신은 그 프레임 워크의 규칙에 의해 놀이에이를, 그렇지 않으면 그 일을하는 것은 좋은 생각이 왜, 어니스트 프리드먼 – 힐의 답변을 참조하십시오.
그러나 run
코드에서 직접 메서드 를 호출 하여 호출 코드에서 예외를 처리 할 수 있다는 직감이 있습니다 .
이 문제에 대한 답은 간단합니다. Runnable
스레드 라이브러리의 인터페이스를 사용하지 말고 대신 확인 된 예외를 throw 할 수 있도록 수정 된 서명으로 자신의 인터페이스를 만듭니다.
public interface MyRunnable
{
void myRun ( ) throws MyException;
}
이 인터페이스를 Runnable
Thread 프레임 워크에서 사용하기에 적합한 실제 (checked exception 처리) 로 변환하는 어댑터를 만들 수도 있습니다 .
답변
당신은을 사용할 수 있습니다 Callable
에 제출, 대신 ExecutorService
과 함께 결과를 기다리고 FutureTask.isDone()
에 의해 반환 ExecutorService.submit()
.
때 isDone()
true를 반환하면 전화 FutureTask.get()
. 당신은 지금, 만약 Callable
던져 않은는 Exception
다음 FutureTask.get()
을 던져 wiill Exception
도 원래 예외는 사용하여 액세스 할 수 있습니다 Exception.getCause()
.
답변
run()
확인 된 예외를 던졌다 면 무엇이 그것을 잡을까요? run()
호출을 호출하는 코드를 작성하지 않기 때문에 해당 호출을 핸들러에 넣을 수있는 방법이 없습니다.
run()
메서드 에서 확인 된 예외를 포착 RuntimeException
하고 그 자리에 체크 되지 않은 예외 (예 :)를 throw 할 수 있습니다 . 스택 추적으로 스레드를 종료합니다. 아마도 그것은 당신이 추구하는 것입니다.
대신 run()
메서드가 어딘가에 오류를보고하도록하려면 run()
메서드의 catch
블록을 호출 할 콜백 메서드를 제공하면 됩니다. 이 메서드는 예외 개체를 어딘가에 저장할 수 있으며 관심있는 스레드는 해당 위치에서 개체를 찾을 수 있습니다.
답변
예, 메서드 에서 확인 된 예외 를 throw하는 run()
방법이 있지만 너무 끔찍해서 공유하지 않을 것입니다.
대신 할 수있는 작업은 다음과 같습니다. 런타임 예외가 실행하는 것과 동일한 메커니즘을 사용합니다.
@Override
public void run() {
try {
/* Do your thing. */
...
} catch (Exception ex) {
Thread t = Thread.currentThread();
t.getUncaughtExceptionHandler().uncaughtException(t, ex);
}
}
다른 사람들이 언급했듯이 run()
메서드가 실제로의 대상 Thread
이면 관찰 할 수 없기 때문에 예외를 throw 할 필요가 없습니다. 예외를 던지는 것은 예외를 던지지 않는 것과 같은 효과가 있습니다 (없음).
그것이 아니라면 Thread
대상, 사용하지 않습니다 Runnable
. 예를 들어, 아마도 Callable
더 적합합니다.
답변
@FunctionalInterface
public interface CheckedRunnable<E extends Exception> extends Runnable {
@Override
default void run() throws RuntimeException {
try {
runThrows();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
void runThrows() throws E;
}
답변
어떤 사람들은 당신이 규칙을 따라야한다고 당신을 설득하려고합니다. 하지만 순종 여부는 상황에 따라 결정해야합니다. 현실은 “규칙에 따라 플레이해야합니다”( “규칙에 따라 플레이해야합니다”가 아님). 규칙을 지키지 않으면 결과가 발생할 수 있습니다.
상황은의 상황 Runnable
뿐만 아니라 Java 8에서도 매우 빈번하게 적용되며 검사 된 예외를 처리 할 가능성없이 기능 인터페이스가 도입 된 Streams 및 기타 장소의 컨텍스트에서도 매우 자주 발생합니다. 예를 들어, Consumer
, Supplier
, Function
, BiFunction
등 모두 체크 된 예외를 처리하는 시설없이 선언합니다.
그렇다면 상황과 옵션은 무엇입니까? 아래 텍스트에서는 Runnable
예외를 선언하지 않거나 당면한 사용 사례에 비해 너무 제한적인 예외를 선언하는 기능 인터페이스를 나타냅니다.
- 당신은
Runnable
어딘가에 선언 했고Runnable
다른 것으로 대체 할 수 있습니다.- 교체 고려
Runnable
와 함께Callable<Void>
. 기본적으로 똑같지 만 예외를 던질 수 있습니다. 보유하고return null
온화한 성가심 끝있다. - 원하는 예외를 정확히 throw 할 수있는
Runnable
사용자 지정으로 교체 하는 것을 고려하십시오@FunctionalInterface
.
- 교체 고려
- API를 사용했으며 대안을 사용할 수 있습니다. 당신이 사용할 수 있도록 예를 들어, 일부 자바 API는 오버로드
Callable<Void>
대신Runnable
. - API를 사용했으며 대안이 없습니다. 이 경우에도 여전히 옵션이 없습니다.
- 에서 예외를 래핑 할 수 있습니다
RuntimeException
. - 체크되지 않은 캐스트를 사용하여 예외를 RuntimeException으로 해킹 할 수 있습니다.
- 에서 예외를 래핑 할 수 있습니다
다음을 시도 할 수 있습니다. 약간의 해킹이지만 때로는 해킹이 필요합니다. 왜냐하면 예외를 확인해야하는지 여부를 확인해야하는지 여부는 유형에 따라 정의되지만 실제로는 상황에 따라 정의되어야하기 때문입니다.
@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
@Override
default void run() {
try {
tryRun();
} catch (final Throwable t) {
throwUnchecked(t);
}
}
private static <E extends RuntimeException> void throwUnchecked(Throwable t) {
throw (E) t;
}
void tryRun() throws Throwable;
}
new RuntimeException(t)
스택 추적이 더 짧기 때문에 이것을 선호 합니다.
이제 다음을 수행 할 수 있습니다.
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
면책 조항 : 이러한 방식으로 확인되지 않은 캐스트를 수행하는 기능은 제네릭 유형 정보가 컴파일 타임뿐만 아니라 런타임에도 처리 될 때 Java의 향후 버전에서 실제로 제거 될 수 있습니다.
답변
귀하의 요구 사항이 의미가 없습니다. 발생한 예외에 대해 스레드의 호출자에게 알리려면 콜백 메커니즘을 통해이를 수행 할 수 있습니다. 이것은 핸들러 나 브로드 캐스트 또는 당신이 생각할 수있는 모든 것을 통할 수 있습니다.