CompletableFuture demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.aruistar.studyjavaten; | |
import org.junit.Test; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.Random; | |
import java.util.concurrent.*; | |
import java.util.stream.Collectors; | |
import static org.junit.Assert.*; | |
/** | |
* https://www.ibm.com/developerworks/cn/java/j-cf-of-jdk8/index.html | |
*/ | |
public class CompletableFutureTest { | |
@Test | |
public void completedFutureExample() { | |
CompletableFuture<String> cf = CompletableFuture.completedFuture("message"); | |
assertTrue(cf.isDone()); | |
assertEquals("message", cf.getNow(null)); | |
} | |
@Test | |
public void runAsyncExample() throws InterruptedException { | |
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> { | |
assertTrue(Thread.currentThread().isDaemon()); | |
randomSleep(); | |
}); | |
assertFalse(cf.isDone()); | |
Thread.sleep(2000); | |
assertTrue(cf.isDone()); | |
} | |
@Test | |
public void thenApplyExample() { | |
CompletableFuture<String> cf = CompletableFuture.completedFuture("message").thenApply(s -> { | |
assertFalse(Thread.currentThread().isDaemon()); | |
return s.toUpperCase(); | |
}); | |
assertEquals("MESSAGE", cf.getNow(null)); | |
} | |
@Test | |
public void thenApplyAsyncExample() { | |
CompletableFuture<String> cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> { | |
assertTrue(Thread.currentThread().isDaemon()); | |
randomSleep(); | |
return s.toUpperCase(); | |
}); | |
assertNull(cf.getNow(null)); | |
assertEquals("MESSAGE", cf.join()); | |
} | |
static ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() { | |
int count = 1; | |
@Override | |
public Thread newThread(Runnable runnable) { | |
return new Thread(runnable, "custom-executor-" + count++); | |
} | |
}); | |
@Test | |
public void thenApplyAsyncWithExecutorExample() { | |
CompletableFuture<String> cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> { | |
assertTrue(Thread.currentThread().getName().startsWith("custom-executor-")); | |
assertFalse(Thread.currentThread().isDaemon()); | |
randomSleep(); | |
return s.toUpperCase(); | |
}, executor); | |
assertNull(cf.getNow(null)); | |
assertEquals("MESSAGE", cf.join()); | |
} | |
@Test | |
public void thenAcceptExample() { | |
StringBuilder result = new StringBuilder(); | |
CompletableFuture.completedFuture("thenAccept message") | |
.thenAccept(s -> result.append(s)); | |
assertEquals(result.toString(), "thenAccept message"); | |
assertTrue("Result was empty", result.length() > 0); | |
} | |
@Test | |
public void thenAcceptAsyncExample() { | |
StringBuilder result = new StringBuilder(); | |
CompletableFuture<Void> cf = CompletableFuture.completedFuture("thenAcceptAsync message") | |
.thenAcceptAsync(s -> result.append(s)); | |
cf.join(); | |
assertTrue("Result was empty", result.length() > 0); | |
} | |
@Test | |
public void completeExceptionallyExample() { | |
CompletableFuture<String> cf = CompletableFuture | |
.completedFuture("message") | |
.thenApplyAsync(String::toUpperCase, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)); | |
CompletableFuture<String> exceptionHandler = cf.handle((s, th) -> (th != null) ? "message upon cancel" : ""); | |
cf.completeExceptionally(new RuntimeException("completed exceptionally")); | |
assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally()); | |
try { | |
cf.join(); | |
fail("Should have thrown an exception"); | |
} catch (CompletionException ex) { // just for testing | |
assertEquals("completed exceptionally", ex.getCause().getMessage()); | |
} | |
assertEquals("message upon cancel", exceptionHandler.join()); | |
} | |
@Test | |
public void cancelExample() { | |
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase, | |
CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)); | |
CompletableFuture cf2 = cf.exceptionally(throwable -> "canceled message"); | |
assertTrue("Was not canceled", cf.cancel(true)); | |
assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally()); | |
assertEquals("canceled message", cf2.join()); | |
} | |
@Test | |
public void applyToEitherExample() { | |
String original = "Message"; | |
CompletableFuture<String> cf1 = CompletableFuture.completedFuture(original) | |
.thenApplyAsync(this::delayedUpperCase); | |
CompletableFuture<String> cf2 = cf1.applyToEither( | |
CompletableFuture.completedFuture(original).thenApplyAsync(this::delayedLowerCase), | |
s -> s + " from applyToEither"); | |
assertEquals(cf2.join(), "MESSAGE from applyToEither"); | |
} | |
@Test | |
public void acceptEitherExample() { | |
String original = "Message"; | |
StringBuilder result = new StringBuilder(); | |
CompletableFuture cf = CompletableFuture.completedFuture(original) | |
.thenApplyAsync(this::delayedUpperCase) | |
.acceptEither(CompletableFuture.completedFuture(original).thenApplyAsync(this::delayedLowerCase), | |
s -> result.append(s).append("acceptEither")); | |
cf.join(); | |
assertTrue("Result was empty", result.toString().endsWith("acceptEither")); | |
} | |
@Test | |
public void runAfterBothExample() { | |
String original = "Message"; | |
StringBuilder result = new StringBuilder(); | |
CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).runAfterBoth( | |
CompletableFuture.completedFuture(original).thenApply(String::toLowerCase), | |
() -> result.append("done")); | |
assertEquals(result.toString(), "messagedone"); | |
assertTrue("Result was empty", result.length() > 0); | |
} | |
@Test | |
public void thenAcceptBothExample() { | |
String original = "Message"; | |
StringBuilder result = new StringBuilder(); | |
CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).thenAcceptBoth( | |
CompletableFuture.completedFuture(original).thenApply(String::toLowerCase), | |
(s1, s2) -> result.append(s1 + s2)); | |
assertEquals("MESSAGEmessage", result.toString()); | |
} | |
@Test | |
public void thenCombineExample() { | |
String original = "Message"; | |
CompletableFuture cf = CompletableFuture.completedFuture(original).thenApply(this::delayedUpperCase) | |
.thenCombine(CompletableFuture.completedFuture(original).thenApply(this::delayedLowerCase), | |
(s1, s2) -> s1 + s2); | |
assertEquals("MESSAGEmessage", cf.getNow(null)); | |
} | |
@Test | |
public void thenCombineAsyncExample() { | |
String original = "Message"; | |
CompletableFuture cf = CompletableFuture.completedFuture(original) | |
.thenApplyAsync(this::delayedUpperCase) | |
.thenCombine(CompletableFuture.completedFuture(original).thenApplyAsync(this::delayedLowerCase), | |
(s1, s2) -> s1 + s2); | |
assertEquals("MESSAGEmessage", cf.join()); | |
} | |
@Test | |
public void thenComposeExample() { | |
String original = "Message"; | |
CompletableFuture cf = CompletableFuture.completedFuture(original).thenApply(this::delayedUpperCase) | |
.thenCompose(upper -> CompletableFuture.completedFuture(original).thenApply(this::delayedLowerCase) | |
.thenApply(s -> upper + s)); | |
assertEquals("MESSAGEmessage", cf.join()); | |
} | |
@Test | |
public void anyOfExample() { | |
StringBuilder result = new StringBuilder(); | |
List<String> messages = Arrays.asList("a", "b", "c"); | |
List<CompletableFuture> futures = messages.stream() | |
.map(msg -> CompletableFuture.completedFuture(msg).thenApply(this::delayedUpperCase)) | |
.collect(Collectors.toList()); | |
CompletableFuture.anyOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete((res, th) -> { | |
if (th == null) { | |
assertTrue(isUpperCase((String) res)); | |
result.append(res); | |
} | |
}); | |
assertTrue("Result was empty", result.length() > 0); | |
} | |
@Test | |
public void allOfExample() { | |
StringBuilder result = new StringBuilder(); | |
List<String> messages = Arrays.asList("a", "b", "c"); | |
List<CompletableFuture> futures = messages.stream() | |
.map(msg -> CompletableFuture.completedFuture(msg).thenApply(s -> delayedUpperCase(s))) | |
.collect(Collectors.toList()); | |
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete((v, th) -> { | |
futures.forEach(cf -> assertTrue(isUpperCase((String) cf.getNow(null)))); | |
result.append("done"); | |
}); | |
System.out.println(result); | |
assertTrue("Result was empty", result.length() > 0); | |
} | |
@Test | |
public void allOfAsyncExample() { | |
StringBuilder result = new StringBuilder(); | |
List<String> messages = Arrays.asList("a", "b", "c"); | |
List<CompletableFuture> futures = messages.stream() | |
.map(msg -> CompletableFuture.completedFuture(msg).thenApplyAsync(this::delayedUpperCase)) | |
.collect(Collectors.toList()); | |
CompletableFuture allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])) | |
.whenComplete((v, th) -> { | |
futures.forEach(cf -> assertTrue(isUpperCase((String) cf.getNow(null)))); | |
result.append("done"); | |
}); | |
allOf.join(); | |
assertTrue("Result was empty", result.length() > 0); | |
} | |
boolean isUpperCase(String s) { | |
return s.toUpperCase().equals(s); | |
} | |
String delayedUpperCase(String s) { | |
randomSleep(); | |
return s.toUpperCase(); | |
} | |
String delayedLowerCase(String s) { | |
randomSleep(); | |
return s.toLowerCase(); | |
} | |
void randomSleep() { | |
try { | |
Thread.sleep(new Random().nextInt(2000)); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks.