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 获取。


原始标题:Introduction to Future in Vavr

» 下一篇: Java 弱引用详解