如何在代码抛出异常时使用 Java 8 CompletableFuture DRY 异常处理?
How to DRY exception handling with Java 8 CompletableFuture when code throws exception?
我不了解你们,但对我来说,当我看到一段代码 repeated
并且在使用 Services
时遇到以下情况时,它变得非常烦人抛出异常。如下所示,在每个 CompletableFuture
块中,我必须执行 exception handling
并且该部分基本上一遍又一遍地重复,具体取决于您将拥有多少可完成的期货。
CompletableFuture<Void> future1Of15 = CompletableFuture.supplyAsync(() -> {
List<SomePojo> somePojos = null;
try {
somePojos = someServiceThatThrowsException.getAll(SomePojo.class);
} catch (SomeException e) {
//Handle the exception
e.printStackTrace();
}
return somePojos;
}).thenAcceptAsync(result -> //do something with the result);
CompletableFuture<Void> future2Of15 = CompletableFuture.supplyAsync(() -> {
List<OtherPojo> otherPojos = null;
try {
otherPojos = someServiceThatThrowsException.getAll(OtherPojo.class);
} catch (SomeException e) {
//Handle the exception
e.printStackTrace();
}
return otherPojos;
}).thenAcceptAsync(result -> //do something with the result);
现在重复上述 x
次,您会注意到 try/catch
块重复了。就我而言,我有大约 15-20
个这样的电话。
有什么方法可以将上面的代码变成一两行代码吗?在supplyAsync lambda
中用stop repeating myself
关于exception handling
?
我并不是说这是唯一的方法或最有效的方法,我正在分享对我有帮助的解决方案 DRY
,它可能对您有用,也可能不适合您。如果您有更好的解决方案,请分享。
我创建了以下实用方法
@Component
public class CompletableFutureUtil {
@Autowired
private SomeGenericServiceThatThrowsException genericService;
public <T> CompletableFuture<Collection<T>> fireupCompletableFutureAsynchronously(Class<T> type) {
CompletableFuture<Collection<T>> future = CompletableFuture.supplyAsync(() -> {
Collection<T> mystery = null;
try {
mystery = genericService.list(type);
} catch (SomeException e) {
e.printStackTrace();
//Handle the exception
}
return mystery;
});
return future;
}
}
现在我可以在 autowiring
之后通过以下方式重用上面的实用方法
@Autowired private CompletableFutureUtil futureUtil;
通话基本上变成一到两行 max
futureUtil.fireupCompletableFutureAsynchronously(SomePojo.class)
.thenAcceptAsync(result -> //do something with result);
futureUtil.fireupCompletableFutureAsynchronously(OtherPojo.class)
.thenAcceptAsync(result -> //do something with result);
快乐DRY+ing
只需向您的 class 添加一个方法来执行所有重复的代码,并在最后一行将 Consumer<List<?>>
作为参数传递给 thenAcceptAsync
。
private CompletableFuture<Void> getAndAcceptAsync(Consumer<List<?>> resultProcessor) {
return CompletableFuture.supplyAsync(() -> {
List<SomePojo> somePojos = null;
try {
somePojos = someServiceThatThrowsException.getAll(SomePojo.class);
} catch (SomeException e) {
//Handle the exception
e.printStackTrace();
}
return somePojos;
}).thenAcceptAsync(resultProcessor);
}
然后您可以根据需要多次调用它。
future1Of15 = getAndAcceptAsync(result-> { do something } );
future2Of15 = getAndAcceptAsync(result-> { do something else } );
有 模式 用于处理效果,例如函数式编程的失败。一种这样的模式是 Try
monad,例如vavr 在 java 中提供了一个实现。
这些模式通过声明性 API 为您抽象出大量样板文件:
CompletableFuture
.supplyAsync(() -> Try.of(() -> methodThatThrows()))
.thenAccept(res -> System.out.println(res));
或者,如果您不必使用 CompletableFuture
,您可以选择使用 Future
monad 来进一步减少样板代码:
Future.of(() -> methodThatThrows())
.onComplete(result -> System.out.println(result));
无论哪种方式,你最终得到的 Future<T>
是一个 Try<T>
,它可以是 Success<T>
或 Failure
,你可以相应处理
我不了解你们,但对我来说,当我看到一段代码 repeated
并且在使用 Services
时遇到以下情况时,它变得非常烦人抛出异常。如下所示,在每个 CompletableFuture
块中,我必须执行 exception handling
并且该部分基本上一遍又一遍地重复,具体取决于您将拥有多少可完成的期货。
CompletableFuture<Void> future1Of15 = CompletableFuture.supplyAsync(() -> {
List<SomePojo> somePojos = null;
try {
somePojos = someServiceThatThrowsException.getAll(SomePojo.class);
} catch (SomeException e) {
//Handle the exception
e.printStackTrace();
}
return somePojos;
}).thenAcceptAsync(result -> //do something with the result);
CompletableFuture<Void> future2Of15 = CompletableFuture.supplyAsync(() -> {
List<OtherPojo> otherPojos = null;
try {
otherPojos = someServiceThatThrowsException.getAll(OtherPojo.class);
} catch (SomeException e) {
//Handle the exception
e.printStackTrace();
}
return otherPojos;
}).thenAcceptAsync(result -> //do something with the result);
现在重复上述 x
次,您会注意到 try/catch
块重复了。就我而言,我有大约 15-20
个这样的电话。
有什么方法可以将上面的代码变成一两行代码吗?在supplyAsync lambda
中用stop repeating myself
关于exception handling
?
我并不是说这是唯一的方法或最有效的方法,我正在分享对我有帮助的解决方案 DRY
,它可能对您有用,也可能不适合您。如果您有更好的解决方案,请分享。
我创建了以下实用方法
@Component
public class CompletableFutureUtil {
@Autowired
private SomeGenericServiceThatThrowsException genericService;
public <T> CompletableFuture<Collection<T>> fireupCompletableFutureAsynchronously(Class<T> type) {
CompletableFuture<Collection<T>> future = CompletableFuture.supplyAsync(() -> {
Collection<T> mystery = null;
try {
mystery = genericService.list(type);
} catch (SomeException e) {
e.printStackTrace();
//Handle the exception
}
return mystery;
});
return future;
}
}
现在我可以在 autowiring
之后通过以下方式重用上面的实用方法
@Autowired private CompletableFutureUtil futureUtil;
通话基本上变成一到两行 max
futureUtil.fireupCompletableFutureAsynchronously(SomePojo.class)
.thenAcceptAsync(result -> //do something with result);
futureUtil.fireupCompletableFutureAsynchronously(OtherPojo.class)
.thenAcceptAsync(result -> //do something with result);
快乐DRY+ing
只需向您的 class 添加一个方法来执行所有重复的代码,并在最后一行将 Consumer<List<?>>
作为参数传递给 thenAcceptAsync
。
private CompletableFuture<Void> getAndAcceptAsync(Consumer<List<?>> resultProcessor) {
return CompletableFuture.supplyAsync(() -> {
List<SomePojo> somePojos = null;
try {
somePojos = someServiceThatThrowsException.getAll(SomePojo.class);
} catch (SomeException e) {
//Handle the exception
e.printStackTrace();
}
return somePojos;
}).thenAcceptAsync(resultProcessor);
}
然后您可以根据需要多次调用它。
future1Of15 = getAndAcceptAsync(result-> { do something } );
future2Of15 = getAndAcceptAsync(result-> { do something else } );
有 模式 用于处理效果,例如函数式编程的失败。一种这样的模式是 Try
monad,例如vavr 在 java 中提供了一个实现。
这些模式通过声明性 API 为您抽象出大量样板文件:
CompletableFuture
.supplyAsync(() -> Try.of(() -> methodThatThrows()))
.thenAccept(res -> System.out.println(res));
或者,如果您不必使用 CompletableFuture
,您可以选择使用 Future
monad 来进一步减少样板代码:
Future.of(() -> methodThatThrows())
.onComplete(result -> System.out.println(result));
无论哪种方式,你最终得到的 Future<T>
是一个 Try<T>
,它可以是 Success<T>
或 Failure
,你可以相应处理