|
|
@ -1,24 +1,26 @@
|
|
|
|
package com.baeldung.completablefuture;
|
|
|
|
package com.baeldung.completablefuture;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.concurrent.*;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
|
|
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.concurrent.CancellationException;
|
|
|
|
|
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
|
|
|
|
import java.util.concurrent.ExecutionException;
|
|
|
|
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
|
|
|
|
import java.util.concurrent.Future;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
|
|
import org.junit.Test;
|
|
|
|
import org.junit.Test;
|
|
|
|
|
|
|
|
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
public class CompletableFutureLongRunningUnitTest {
|
|
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class CompletableFutureTest {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenRunningCompletableFutureAsynchronously_thenGetMethodWaitsForResult() throws InterruptedException, ExecutionException {
|
|
|
|
public void whenRunningCompletableFutureAsynchronously_thenGetMethodWaitsForResult() throws InterruptedException, ExecutionException {
|
|
|
|
|
|
|
|
|
|
|
|
Future<String> completableFuture = calculateAsync();
|
|
|
|
Future<String> completableFuture = calculateAsync();
|
|
|
|
|
|
|
|
|
|
|
|
String result = completableFuture.get();
|
|
|
|
String result = completableFuture.get();
|
|
|
|
assertEquals("Hello", result);
|
|
|
|
assertEquals("Hello", result);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Future<String> calculateAsync() throws InterruptedException {
|
|
|
|
public Future<String> calculateAsync() throws InterruptedException {
|
|
|
@ -35,12 +37,10 @@ public class CompletableFutureTest {
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenRunningCompletableFutureWithResult_thenGetMethodReturnsImmediately() throws InterruptedException, ExecutionException {
|
|
|
|
public void whenRunningCompletableFutureWithResult_thenGetMethodReturnsImmediately() throws InterruptedException, ExecutionException {
|
|
|
|
|
|
|
|
|
|
|
|
Future<String> completableFuture = CompletableFuture.completedFuture("Hello");
|
|
|
|
Future<String> completableFuture = CompletableFuture.completedFuture("Hello");
|
|
|
|
|
|
|
|
|
|
|
|
String result = completableFuture.get();
|
|
|
|
String result = completableFuture.get();
|
|
|
|
assertEquals("Hello", result);
|
|
|
|
assertEquals("Hello", result);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Future<String> calculateAsyncWithCancellation() throws InterruptedException {
|
|
|
|
public Future<String> calculateAsyncWithCancellation() throws InterruptedException {
|
|
|
@ -57,82 +57,65 @@ public class CompletableFutureTest {
|
|
|
|
|
|
|
|
|
|
|
|
@Test(expected = CancellationException.class)
|
|
|
|
@Test(expected = CancellationException.class)
|
|
|
|
public void whenCancelingTheFuture_thenThrowsCancellationException() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenCancelingTheFuture_thenThrowsCancellationException() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
Future<String> future = calculateAsyncWithCancellation();
|
|
|
|
Future<String> future = calculateAsyncWithCancellation();
|
|
|
|
future.get();
|
|
|
|
future.get();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenCreatingCompletableFutureWithSupplyAsync_thenFutureReturnsValue() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenCreatingCompletableFutureWithSupplyAsync_thenFutureReturnsValue() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello", future.get());
|
|
|
|
assertEquals("Hello", future.get());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenAddingThenAcceptToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenAddingThenAcceptToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<Void> future = completableFuture.thenAccept(s -> System.out.println("Computation returned: " + s));
|
|
|
|
CompletableFuture<Void> future = completableFuture.thenAccept(s -> System.out.println("Computation returned: " + s));
|
|
|
|
|
|
|
|
|
|
|
|
future.get();
|
|
|
|
future.get();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenAddingThenRunToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenAddingThenRunToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<Void> future = completableFuture.thenRun(() -> System.out.println("Computation finished."));
|
|
|
|
CompletableFuture<Void> future = completableFuture.thenRun(() -> System.out.println("Computation finished."));
|
|
|
|
|
|
|
|
|
|
|
|
future.get();
|
|
|
|
future.get();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenAddingThenApplyToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenAddingThenApplyToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> future = completableFuture.thenApply(s -> s + " World");
|
|
|
|
CompletableFuture<String> future = completableFuture.thenApply(s -> s + " World");
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello World", future.get());
|
|
|
|
assertEquals("Hello World", future.get());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenUsingThenCompose_thenFuturesExecuteSequentially() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenUsingThenCompose_thenFuturesExecuteSequentially() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello").thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello").thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello World", completableFuture.get());
|
|
|
|
assertEquals("Hello World", completableFuture.get());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenUsingThenCombine_thenWaitForExecutionOfBothFutures() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenUsingThenCombine_thenWaitForExecutionOfBothFutures() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello").thenCombine(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> s1 + s2);
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello").thenCombine(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> s1 + s2);
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello World", completableFuture.get());
|
|
|
|
assertEquals("Hello World", completableFuture.get());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenUsingThenAcceptBoth_thenWaitForExecutionOfBothFutures() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenUsingThenAcceptBoth_thenWaitForExecutionOfBothFutures() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture.supplyAsync(() -> "Hello").thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> System.out.println(s1 + s2));
|
|
|
|
CompletableFuture.supplyAsync(() -> "Hello").thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> System.out.println(s1 + s2));
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenFutureCombinedWithAllOfCompletes_thenAllFuturesAreDone() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenFutureCombinedWithAllOfCompletes_thenAllFuturesAreDone() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Beautiful");
|
|
|
|
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Beautiful");
|
|
|
|
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "World");
|
|
|
|
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "World");
|
|
|
@ -150,12 +133,10 @@ public class CompletableFutureTest {
|
|
|
|
String combined = Stream.of(future1, future2, future3).map(CompletableFuture::join).collect(Collectors.joining(" "));
|
|
|
|
String combined = Stream.of(future1, future2, future3).map(CompletableFuture::join).collect(Collectors.joining(" "));
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello Beautiful World", combined);
|
|
|
|
assertEquals("Hello Beautiful World", combined);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenFutureThrows_thenHandleMethodReceivesException() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenFutureThrows_thenHandleMethodReceivesException() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
String name = null;
|
|
|
|
String name = null;
|
|
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
// ...
|
|
|
@ -168,12 +149,10 @@ public class CompletableFutureTest {
|
|
|
|
}).handle((s, t) -> s != null ? s : "Hello, Stranger!");
|
|
|
|
}).handle((s, t) -> s != null ? s : "Hello, Stranger!");
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello, Stranger!", completableFuture.get());
|
|
|
|
assertEquals("Hello, Stranger!", completableFuture.get());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test(expected = ExecutionException.class)
|
|
|
|
@Test(expected = ExecutionException.class)
|
|
|
|
public void whenCompletingFutureExceptionally_thenGetMethodThrows() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenCompletingFutureExceptionally_thenGetMethodThrows() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = new CompletableFuture<>();
|
|
|
|
CompletableFuture<String> completableFuture = new CompletableFuture<>();
|
|
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
// ...
|
|
|
@ -183,18 +162,15 @@ public class CompletableFutureTest {
|
|
|
|
// ...
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
|
|
completableFuture.get();
|
|
|
|
completableFuture.get();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
public void whenAddingThenApplyAsyncToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
public void whenAddingThenApplyAsyncToFuture_thenFunctionExecutesAfterComputationIsFinished() throws ExecutionException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello");
|
|
|
|
|
|
|
|
|
|
|
|
CompletableFuture<String> future = completableFuture.thenApplyAsync(s -> s + " World");
|
|
|
|
CompletableFuture<String> future = completableFuture.thenApplyAsync(s -> s + " World");
|
|
|
|
|
|
|
|
|
|
|
|
assertEquals("Hello World", future.get());
|
|
|
|
assertEquals("Hello World", future.get());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|