CompletableFuture的用法
CompletableFuture
是 Java 8 引入的一个类,用于处理异步编程。它提供了丰富的 API 来处理异步任务的执行、组合和处理结果。以下是 CompletableFuture
的一些常见用法:
1. 创建 CompletableFuture
- 直接创建一个完成的
CompletableFuture
:
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("Hello");
- 通过异步任务创建
CompletableFuture
:
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 异步任务
System.out.println("Running in a separate thread");
});
2. 组合多个 CompletableFuture
- 使用
thenApply
处理结果:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(result -> result + " World");
- 使用
thenAccept
处理结果,无返回值:
CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(result -> System.out.println(result + " World"));
- 使用
thenCompose
链接多个异步任务:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
- 使用
thenCombine
合并两个CompletableFuture
的结果:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
3. 处理异常
- 使用
exceptionally
处理异常:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("Exception occurred");
}
return "Hello";
}).exceptionally(ex -> "Error: " + ex.getMessage());
- 使用
handle
处理结果和异常:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("Exception occurred");
}
return "Hello";
}).handle((result, ex) -> {
if (ex != null) {
return "Error: " + ex.getMessage();
}
return result;
});
4. 等待所有任务完成
- 使用
allOf
等待所有CompletableFuture
完成:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2);
allOf.thenRun(() -> {
try {
System.out.println(future1.get() + " " + future2.get());
} catch (Exception e) {
e.printStackTrace();
}
});
5. 等待任意一个任务完成
- 使用
anyOf
等待任意一个CompletableFuture
完成:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2);
anyOf.thenAccept(result -> System.out.println(result));
6. 超时处理
- 使用
orTimeout
设置超时:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
}).orTimeout(1, TimeUnit.SECONDS).exceptionally(ex -> "Timeout: " + ex.getMessage());
- 使用
completeOnTimeout
设置超时并提供默认值:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
}).completeOnTimeout("Default Value", 1, TimeUnit.SECONDS);
总结
CompletableFuture
提供了丰富的 API 来处理异步任务,包括任务的创建、组合、异常处理、超时处理等。通过这些 API,你可以轻松地实现复杂的异步编程逻辑。
如何获取异步执行的结果
在 Java 中,CompletableFuture
提供了多种方式来获取异步执行的结果。以下是几种常见的方法:
-
get()
方法:
这是最常用的方法之一。它会阻塞当前线程,直到CompletableFuture
完成并返回结果。CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务 return "Hello, World!"; }); try { String result = future.get(); System.out.println(result); // 输出: Hello, World! } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
-
join()
方法:
类似于get()
方法,但它会抛出未经检查的异常(CompletionException
),而不是受检异常。CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务 return "Hello, World!"; }); String result = future.join(); System.out.println(result); // 输出: Hello, World!
-
thenApply()
方法:
该方法允许在CompletableFuture
完成后对结果进行处理,并返回一个新的CompletableFuture
。CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务 return "Hello, World!"; }); CompletableFuture<String> processedFuture = future.thenApply(result -> { return result + " Processed!"; }); String processedResult = processedFuture.join(); System.out.println(processedResult); // 输出: Hello, World! Processed!
-
thenAccept()
方法:
该方法允许在CompletableFuture
完成后对结果进行消费,但不返回新的CompletableFuture
。CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务 return "Hello, World!"; }); future.thenAccept(result -> { System.out.println(result); // 输出: Hello, World! });
-
whenComplete()
方法:
该方法允许在CompletableFuture
完成后执行一个回调,无论是正常完成还是异常完成。CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务 return "Hello, World!"; }); future.whenComplete((result, exception) -> { if (exception == null) { System.out.println(result); // 输出: Hello, World! } else { exception.printStackTrace(); } });
-
handle()
方法:
该方法允许在CompletableFuture
完成后对结果或异常进行处理,并返回一个新的CompletableFuture
。CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { // 异步任务 return "Hello, World!"; }); CompletableFuture<String> handledFuture = future.handle((result, exception) -> { if (exception == null) { return result + " Handled!"; } else { return "Exception occurred!"; } }); String handledResult = handledFuture.join(); System.out.println(handledResult); // 输出: Hello, World! Handled!
void类型,调用get方法后
如果 CompletableFuture
的类型是 Void
,你仍然可以使用 get()
方法来等待异步任务的完成。尽管 get()
方法会返回 null
,但它会确保异步任务已经完成。
以下是一个示例:
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 异步任务
System.out.println("Task is running");
});
try {
// 调用 get() 方法等待任务完成
future.get();
System.out.println("Task completed");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
在这个示例中,CompletableFuture.runAsync()
方法创建了一个异步任务,该任务不返回任何结果(即 Void
类型)。调用 get()
方法会阻塞当前线程,直到异步任务完成。
其他获取 Void
类型 CompletableFuture
结果的方法:
-
join()
方法:
类似于get()
方法,但它会抛出未经检查的异常(CompletionException
),而不是受检异常。CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 异步任务 System.out.println("Task is running"); }); // 调用 join() 方法等待任务完成 future.join(); System.out.println("Task completed");
-
thenRun()
方法:
该方法允许在CompletableFuture
完成后执行一个回调,但不返回新的CompletableFuture
。CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 异步任务 System.out.println("Task is running"); }); future.thenRun(() -> { System.out.println("Task completed"); });
-
whenComplete()
方法:
该方法允许在CompletableFuture
完成后执行一个回调,无论是正常完成还是异常完成。CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 异步任务 System.out.println("Task is running"); }); future.whenComplete((result, exception) -> { if (exception == null) { System.out.println("Task completed"); } else { exception.printStackTrace(); } });
-
handle()
方法:
该方法允许在CompletableFuture
完成后对结果或异常进行处理,并返回一个新的CompletableFuture
。CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 异步任务 System.out.println("Task is running"); }); CompletableFuture<Void> handledFuture = future.handle((result, exception) -> { if (exception == null) { System.out.println("Task completed"); } else { System.out.println("Exception occurred"); } return null; }); // 调用 join() 方法等待处理完成 handledFuture.join();
如果不需要等待返回值
如果不需要等待 CompletableFuture
的返回值,只需要启动异步任务并继续执行后续代码,可以使用以下几种方法:
-
runAsync()
方法:
该方法用于启动一个不返回结果的异步任务。CompletableFuture.runAsync(() -> { // 异步任务 System.out.println("Task is running"); }); // 后续代码 System.out.println("Task has been started");
-
supplyAsync()
方法:
该方法用于启动一个返回结果的异步任务,但你可以忽略返回值。CompletableFuture.supplyAsync(() -> { // 异步任务 System.out.println("Task is running"); return "Result"; }); // 后续代码 System.out.println("Task has been started");
-
链式调用:
如果你需要在异步任务完成后执行一些操作,但不需要等待结果,可以使用thenRun()
或thenAccept()
方法。CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 异步任务 System.out.println("Task is running"); }); future.thenRun(() -> { // 异步任务完成后的操作 System.out.println("Task completed"); }); // 后续代码 System.out.println("Task has been started");
-
组合多个异步任务:
如果你有多个异步任务,并且不需要等待它们的结果,可以使用allOf()
方法。CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { // 异步任务1 System.out.println("Task 1 is running"); }); CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> { // 异步任务2 System.out.println("Task 2 is running"); }); CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2); allFutures.thenRun(() -> { // 所有异步任务完成后的操作 System.out.println("All tasks completed"); }); // 后续代码 System.out.println("Tasks have been started");
总结:如果你不需要等待 CompletableFuture
的返回值,只需要启动异步任务并继续执行后续代码,可以直接调用 runAsync()
或 supplyAsync()
方法,并在需要时使用链式调用来处理任务完成后的操作。这样可以确保异步任务在后台执行,而主线程继续执行后续代码。