2016-10-31 2 views
1

CompletableFuture 체인을 가지고 놀고있어 (적어도 나를 위해) 예기치 않은 비헤이비어가있는 상황을 발견했습니다. .thenCompose() 호출에서 예외적 인 CompletableFuture가 전달 된 경우 원래 CompletableFuture가 래핑 된 원래 예외로 완료됩니다 CompletionException. 예를 들어없이 이해하기 어려울 수 있습니다 : 물론원하는 CompletableFuture 비헤이비어 적용

public static <T> CompletableFuture<T> exceptional(Throwable error) { 
    CompletableFuture<T> future = new CompletableFuture<>(); 
    future.completeExceptionally(error); 
    return future; 
} 

public static void main(String[] args) { 
    CompletableFuture<Void> exceptional = exceptional(new RuntimeException()); 
    exceptional 
      .handle((result, throwable) -> { 
       System.out.println(throwable); 
       // java.lang.RuntimeException 

       System.out.println(throwable.getCause()); 
       // null 

       return null; 
      }); 

    CompletableFuture 
      .completedFuture(null) 
      .thenCompose(v -> exceptional) 
      .handle((result, throwable) -> { 
       System.out.println(throwable); 
       // java.util.concurrent.CompletionException: java.lang.RuntimeException 

       System.out.println(throwable.getCause()); 
       // java.lang.RuntimeException 

       return null; 
      }); 
} 

내가 상관없이 전이나 체인 후에 얼마나 많은 변환 같은 RuntimeException 처리하지 기대했다. 두 가지 질문이 있습니다.

  • 예상되는 동작입니까?
  • 수동 언 랩핑을 제외하고 원래 예외가 계속 유지되는 옵션이 있습니까? thenCompose()위한

답변

2

Javadoc의 은 :

이 단계가 정상적으로 완료되면, 공급 함수의 인수로서,이 단계로 실행되고, 새로운 CompletionStage을 반환. 예외적 인 완료를 다루는 규칙은 CompletionStage 설명서를 참조하십시오.

과 계면 상태의 정의 :

단계의 계산은 (체크) 예외 또는 오류가 갑자기 종료되면

[...]은 모든 다른 경우에, 모든 종속 단계는 완료 필요 예외적으로 그 원인으로 예외를 보유한 CompletionException으로 예외적으로 완료하십시오. [...]

thenCompose로 돌아 종속 단계는, 이 된 동작을 것으로 예상된다. 당신이 당신의 예외를 포장 것 같은 supplyAsync()completeExceptionally(), cancel() 등도 방법과 같은 방법으로 명시 적으로 CompletableFuture를 완료하면

는 사실, 당신이 CompletionException보다는 다른 뭔가를 할 수있는 유일한 경우입니다.

getCause()으로 처리하기 쉽기 때문에 원래 예외에 액세스하는 다른 옵션은 없다고 생각합니다. 당신이 정말로 자주 할 필요가있는 경우, 당신은 같은 도우미 메서드를 작성할 수

public static <T, U> BiFunction<? super T, Throwable, ? extends U> 
     unwrappingCompletionException(BiFunction<? super T, Throwable, ? extends U> fn) { 
    return (t, u) -> { 
     if (u instanceof CompletionException) { 
      return fn.apply(t, u.getCause()); 
     } 
     return fn.apply(t, u); 
    }; 
} 

하고 다음과 같이 사용합니다

CompletableFuture 
     .completedFuture(null) 
     .thenCompose(v -> exceptional) 
     .handle(unwrappingCompletionException((result, throwable) -> { 
      […] 
     })); 
관련 문제