我试图在循环中为PUT
请求调用rest api。每个呼叫都是一个CompletableFuture
。每个api调用都会返回一个RoomTypes.RoomType
我想收集响应(成功和错误都
回复)在不同的列表中。我该如何实现?我确定我
无法使用allOf
,因为它将无法获得所有结果
一个呼叫无法更新。
如何记录每个呼叫的错误/异常?
public void sendRequestsAsync(Map<Integer, List> map1) {
List<CompletableFuture<Void>> completableFutures = new ArrayList<>(); //List to hold all the completable futures
List<RoomTypes.RoomType> responses = new ArrayList<>(); //List for responses
ExecutorService yourOwnExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (Map.Entry<Integer, List> entry :map1.entrySet()) {
CompletableFuture requestCompletableFuture = CompletableFuture
.supplyAsync(
() ->
//API call which returns object of type RoomTypes.RoomType
updateService.updateRoom(51,33,759,entry.getKey(),
new RoomTypes.RoomType(entry.getKey(),map2.get(entry.getKey()),
entry.getValue())),
yourOwnExecutor
)//Supply the task you wanna run, in your case http request
.thenApply(responses::add);
completableFutures.add(requestCompletableFuture);
}
答案 0 :(得分:6)
您可以简单地使用allOf()
来获得一个在所有初始期货都完成后(无论是否异常)都完成的期货,然后使用Collectors.partitioningBy()
在成功和失败之间进行划分:
List<CompletableFuture<RoomTypes.RoomType>> completableFutures = new ArrayList<>(); //List to hold all the completable futures
ExecutorService yourOwnExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (Map.Entry<Integer, List> entry : map1.entrySet()) {
CompletableFuture<RoomTypes.RoomType> requestCompletableFuture = CompletableFuture
.supplyAsync(
() ->
//API call which returns object of type RoomTypes.RoomType
updateService.updateRoom(51, 33, 759, entry.getKey(),
new RoomTypes.RoomType(entry.getKey(), map2.get(entry.getKey()),
entry.getValue())),
yourOwnExecutor
);
completableFutures.add(requestCompletableFuture);
}
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]))
// avoid throwing an exception in the join() call
.exceptionally(ex -> null)
.join();
Map<Boolean, List<CompletableFuture<RoomTypes.RoomType>>> result =
completableFutures.stream()
.collect(Collectors.partitioningBy(CompletableFuture::isCompletedExceptionally)));
生成的地图将包含一个带有true
的条目用于失败的期货,以及另一个带有false
密钥的条目用于成功的期货。然后,您可以检查2个条目以采取相应的措施。
请注意,与原始代码相比,有2个细微变化:
requestCompletableFuture
现在是CompletableFuture<RoomTypes.RoomType>
thenApply(responses::add)
和responses
列表已删除关于日志记录/异常处理,只需添加相关的requestCompletableFuture.handle()
即可分别记录它们,但保留requestCompletableFuture
而不是handle()
产生的记录。
答案 1 :(得分:3)
或者,也许您可以从不同的角度解决问题,而不是强制使用ID First Name Last Name
1 Mark Taylor
2 James Bond
,而可以使用JSFiddle。
CompletableFuture
的整个想法是,一旦对给定未来的答案已经准备好,它将被排入队列,您可以从中使用结果。
替代方法1:没有CompletableFuture
CompletionService
哪种产量:
CompletionService<String> cs = new ExecutorCompletionService<>(executor);
List<Future<String>> futures = new ArrayList<>();
futures.add(cs.submit(() -> "One"));
futures.add(cs.submit(() -> "Two"));
futures.add(cs.submit(() -> "Three"));
futures.add(cs.submit(() -> { throw new RuntimeException("Sucks to be four"); }));
futures.add(cs.submit(() -> "Five"));
List<String> successes = new ArrayList<>();
List<String> failures = new ArrayList<>();
while (futures.size() > 0) {
Future<String> f = cs.poll();
if (f != null) {
futures.remove(f);
try {
//at this point the future is guaranteed to be solved
//so there won't be any blocking here
String value = f.get();
successes.add(value);
} catch (Exception e) {
failures.add(e.getMessage());
}
}
}
System.out.println(successes);
System.out.println(failures);
替代2:具有CompletableFuture
但是,如果确实需要处理[One, Two, Three, Five]
[java.lang.RuntimeException: Sucks to be four]
,您也可以将它们直接提交到完成服务中,只需将它们直接放入队列中即可。
例如,以下变体具有相同的结果:
CompletableFuture