1. 引言
Java 核心库提供了基础的异步计算 API —— Future
。其中 CompletableFuture
是较新的实现之一。Vavr 则提供了其函数式风格的替代方案。本文将深入探讨 Vavr 的 Future
API,并通过实际示例演示其核心功能。
✅ 快速了解 Vavr 更多功能:可以参考 Vavr 教程合集
2. Maven 依赖
Vavr 的 Future
API 已包含在核心依赖中。添加到 pom.xml
:
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.9.2</version>
</dependency>
💡 最新版本可在 Maven Central 查询
3. Vavr 的 Future
Future 只存在两种状态:
- Pending:计算进行中
- Completed:计算完成(成功返回结果/失败抛异常/被取消)
相比 Java 原生 Future 的核心优势:
可以轻松注册回调函数,并以非阻塞方式组合操作。
4. 基础 Future 操作
4.1 启动异步计算
使用 Vavr 启动异步任务:
String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> someComputation());
4.2 从 Future 获取值
通过 get()
或 getOrElse()
提取值:
String result = resultFuture.getOrElse("Failed to get underlying value.");
⚠️ 关键区别:
get()
:简单直接,异常时抛出getOrElse()
:异常时返回默认值,推荐使用
📌 注意:
get()
会阻塞线程直到结果就绪
非阻塞方式使用 getValue()
:
Option<Try<String>> futureOption = resultFuture.getValue();
Try<String> futureTry = futureOption.get();
String result = futureTry.get();
检查 Future 是否包含值(阻塞操作):
resultFuture.isEmpty(); // 阻塞直到完成
4.3 自定义线程池
默认使用 Executors.newCachedThreadPool()
,可替换为自定义实现:
@Test
public void whenChangeExecutorService_thenCorrect() {
String result = Future.of(newSingleThreadExecutor(), () -> HELLO)
.getOrElse(error);
assertThat(result)
.isEqualTo(HELLO);
}
5. 完成后的回调处理
onSuccess()
:成功时触发onFailure()
:失败时触发
Future<String> resultFuture = Future.of(() -> appendData(initialValue))
.onSuccess(v -> System.out.println("成功完成 - 结果: " + v))
.onFailure(v -> System.out.println("执行失败 - 结果: " + v));
onComplete()
和 andThen()
在完成时触发(无论成功失败),后者保证顺序执行:
Future<String> resultFuture = Future.of(() -> appendData(initialValue))
.andThen(finalResult -> System.out.println("完成 - 1: " + finalResult))
.andThen(finalResult -> System.out.println("完成 - 2: " + finalResult));
6. 实用 Future 操作
6.1 阻塞当前线程
await()
行为:
- Pending 时阻塞直到完成
- 已完成时立即返回
resultFuture.await(); // 简单粗暴的阻塞等待
6.2 取消计算
随时取消任务:
resultFuture.cancel();
6.3 获取底层线程池
resultFuture.executorService(); // 返回 ExecutorService 实例
6.4 获取失败异常
通过 getCause()
获取 Throwable
:
@Test
public void whenDivideByZero_thenGetThrowable2() {
Future<Integer> resultFuture = Future.of(() -> 10 / 0)
.await();
assertThat(resultFuture.getCause().get().getMessage())
.isEqualTo("/ by zero");
}
或使用 failed()
转换为失败 Future:
@Test
public void whenDivideByZero_thenGetThrowable1() {
Future<Integer> resultFuture = Future.of(() -> 10 / 0);
assertThatThrownBy(resultFuture::get)
.isInstanceOf(ArithmeticException.class);
}
6.5 状态检查方法
三个自解释方法:
isCompleted()
:是否完成isSuccess()
:是否成功isFailure()
:是否失败
@Test
public void whenDivideByZero_thenCorrect() {
Future<Integer> resultFuture = Future.of(() -> 10 / 0)
.await();
assertThat(resultFuture.isCompleted()).isTrue();
assertThat(resultFuture.isSuccess()).isFalse();
assertThat(resultFuture.isFailure()).isTrue();
}
6.6 链式计算操作
map()
应用函数到结果:
@Test
public void whenCallMap_thenCorrect() {
Future<String> futureResult = Future.of(() -> "from Baeldung")
.map(a -> "Hello " + a)
.await();
assertThat(futureResult.get())
.isEqualTo("Hello from Baeldung");
}
避免嵌套 Future 使用 flatMap()
:
@Test
public void whenCallFlatMap_thenCorrect() {
Future<Object> futureMap = Future.of(() -> 1)
.flatMap((i) -> Future.of(() -> "Hello: " + i));
assertThat(futureMap.get()).isEqualTo("Hello: 1");
}
6.7 转换 Future 值
transformValue()
改变值类型:
@Test
public void whenTransform_thenCorrect() {
Future<Object> future = Future.of(() -> 5)
.transformValue(result -> Try.of(() -> HELLO + result.get()));
assertThat(future.get()).isEqualTo(HELLO + 5);
}
6.8 合并 Future
zip()
将多个 Future 合并为元组:
@Test
public void whenCallZip_thenCorrect() {
Future<String> f1 = Future.of(() -> "hello1");
Future<String> f2 = Future.of(() -> "hello2");
assertThat(f1.zip(f2).get())
.isEqualTo(Tuple.of("hello1", "hello2"));
}
⚠️ 只要有一个 Future 未完成,结果 Future 就保持 Pending
6.9 与 CompletableFuture 互转
转换 Vavr Future 为 Java 原生 CompletableFuture:
@Test
public void whenConvertToCompletableFuture_thenCorrect()
throws Exception {
CompletableFuture<String> convertedFuture = Future.of(() -> HELLO)
.toCompletableFuture();
assertThat(convertedFuture.get())
.isEqualTo(HELLO);
}
反向转换使用 fromCompletableFuture()
。
6.10 异常处理
recover()
提供默认值:
@Test
public void whenFutureFails_thenGetErrorMessage() {
Future<String> future = Future.of(() -> "Hello".substring(-1))
.recover(x -> "fallback value");
assertThat(future.get())
.isEqualTo("fallback value");
}
recoverWith()
返回另一个 Future:
@Test
public void whenFutureFails_thenGetAnotherFuture() {
Future<String> future = Future.of(() -> "Hello".substring(-1))
.recoverWith(x -> Future.of(() -> "fallback value"));
assertThat(future.get())
.isEqualTo("fallback value");
}
fallbackTo()
优先级降级处理:
@Test
public void whenBothFuturesFail_thenGetErrorMessage() {
Future<String> f1 = Future.of(() -> "Hello".substring(-1));
Future<String> f2 = Future.of(() -> "Hello".substring(-2));
Future<String> errorMessageFuture = f1.fallbackTo(f2);
Future<Throwable> errorMessage = errorMessageFuture.failed();
assertThat(
errorMessage.get().getMessage())
.isEqualTo("begin -1, end 5, length 5");
}
7. 总结
本文深入探讨了 Vavr Future 的核心概念与实用技巧,通过示例演示了:
- 异步任务启动与结果获取
- 回调机制与线程池定制
- 丰富的链式操作与异常处理
- 与 Java 原生 API 的互操作
完整代码示例可在 GitHub 获取。