包装器
概述
有些使用场景下偏向于把Chance
封装为面向线程池可执行的Callable
实例,而Chance
天然支持这个特性,简单通过wrap()
方法进行包装即可。
使用详解
java
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Chance<String> chance = Chance.<String, Throwable>newBuilder()
.withNeverRetry()
.withRecoverIfHasException()
.withRecovery(attempt -> "Recovery")
.build();
Callable<String> c1 = chance.wrap(() -> "Hello");
Callable<String> c2 = chance.wrap(() -> {
}, "World");
Future<String> f1 = executorService.submit(c1);
Future<String> f2 = executorService.submit(c2);
System.out.printf("result of f1: %s, result of f2: %s\n", f1.get(), f2.get());
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS);
}
上面的代码最终输出结果:
shell
result of f1: Hello, result of f2: World
异常处理
对于使用包装器异步执行的场景,异常处理会有些不同。Future
的异常处理会包裹Chance
抛出的异常,例如:
java
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Chance<String> chance = Chance.<String, Throwable>newBuilder()
.withNeverRetry()
.build();
Callable<String> c3 = chance.wrap(() -> {
throw new RuntimeException("Error");
});
executorService.submit(c3).get();
}
执行上面的代码会看到类似下面的异常栈:
shell
Exception in thread "main" java.util.concurrent.ExecutionException: cn.vlts.chance.ChanceException:
Retrying calling failed after 1 attempts. Exception message: Error.
想要获取根异常可以考虑使用Chance
提供的Utils.U.getRootCause()
方法对异常进行提取,从而获取最内层的RuntimeException
。采用包装器在非超时或者中断异常的前提下,异常的层次基本如下:
shell
ExecutionException -> ChanceException -> Root Exception