FULL PRODUCT VERSION : java version "1.8.0_25" Java(TM) SE Runtime Environment (build 1.8.0_25-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode) ADDITIONAL OS VERSION INFORMATION : Linux 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux A DESCRIPTION OF THE PROBLEM : CompletableFuture.thenCompose inconsistently handles exception thrown from the CompletionStage created by function. See the steps to reproduce STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : I have this two tests that only differ in order of execution but produce different output. @Test public void completedAfter() { CompletableFuture<String> future1 = new CompletableFuture<>(); CompletableFuture<String> future2 = new CompletableFuture<>(); future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("After: " + e)); future1.complete("value"); future2.completeExceptionally(new RuntimeException()); } @Test public void completedBefore() { CompletableFuture<String> future1 = new CompletableFuture<>(); CompletableFuture<String> future2 = new CompletableFuture<>(); future1.complete("value"); future2.completeExceptionally(new RuntimeException()); future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("Before: " +e)); } EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - Consistent output, most likely: After: java.util.concurrent.CompletionException: java.lang.RuntimeException Before: java.util.concurrent.CompletionException: java.lang.RuntimeException ACTUAL - Inconsistent output: After: java.util.concurrent.CompletionException: java.lang.RuntimeException Before: java.lang.RuntimeException REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import org.junit.Test; import java.util.concurrent.CompletableFuture; public class CompletableFutureComposeTest { @Test public void completedAfter() { CompletableFuture<String> future1 = new CompletableFuture<>(); CompletableFuture<String> future2 = new CompletableFuture<>(); future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("After: " + e)); future1.complete("value"); future2.completeExceptionally(new RuntimeException()); } @Test public void completedBefore() { CompletableFuture<String> future1 = new CompletableFuture<>(); CompletableFuture<String> future2 = new CompletableFuture<>(); future1.complete("value"); future2.completeExceptionally(new RuntimeException()); future1.thenCompose(x -> future2).whenComplete((r, e) -> System.out.println("Before: " +e)); } } ---------- END SOURCE ----------
|