我必须运行多个外部调用操作,然后以列表的形式获得结果。我决定使用completablefuture
api,而我准备的代码相当恶心:
示例:
public class Main {
public static void main(String[] args) {
String prefix = "collection_";
List<CompletableFuture<User>> usersResult = IntStream.range(1, 10)
.boxed()
.map(num -> prefix.concat("" + num))
.map(name -> CompletableFuture.supplyAsync(
() -> callApi(name)))
.collect(Collectors.toList());
try {
CompletableFuture.allOf(usersResult.toArray(new CompletableFuture[usersResult.size()])).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
List<User> users = usersResult //the result I need
.stream()
.map(userCompletableFuture -> {
try {
return userCompletableFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
private static User callApi(String collection) {
return new User(); //potentially time-consuming operation
}
}
我有以下几个问题:
>
try-catch
块吗?在流中我将CompletableFuture映射到User?这样做可以吗(所有的未来都将在流中解决吗?):
public class Main {
public static void main(String[] args) {
String prefix = "collection_";
List<User> usersResult = IntStream.range(1, 10)
.boxed()
.map(num -> prefix.concat("" + num))
.map(name -> CompletableFuture.supplyAsync(
() -> callApi(name)))
.filter(Objects::nonNull)
.map(userCompletableFuture -> {
try {
return userCompletableFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
})
.collect(Collectors.toList());
}
private static User callApi(String collection) {
return new User(); //potentially time-consuming operation
}
}
对于1.,您可以完全跳过ALLOF().GET()
调用,因为您仍然在逐个等待所有未来。“
对于2.,您可以通过执行以下操作来简化try-catch
:
exceptionaly()
在将来直接处理异常;join()
而不是get()
来避免检查异常(并且您知道不可能有异常)。对于3.你不能真的减少它的顺序,因为你至少需要步骤:创建所有的未来,然后处理他们的结果。
如果您在一个流中执行所有操作,它将创建每个未来,然后在创建下一个之前立即等待它--这样您就会失去并行性。您可以使用并行流,但使用completablefuture
s并没有太大的好处。
所以最终的代码是:
List<CompletableFuture<User>> usersResult = IntStream.range(1, 10)
.boxed()
.map(num -> prefix.concat("" + num))
.map(name -> CompletableFuture.supplyAsync(() -> callApi(name))
.exceptionally(e -> {
e.printStackTrace();
return null;
}))
.collect(Collectors.toList());
List<User> users = usersResult
.stream()
.map(CompletableFuture::join)
.filter(Objects::nonNull)
.collect(Collectors.toList());
“注意,如果希望您的结果也是completablefuture
,则仍然需要allof()
调用,例如。
final CompletableFuture<List<User>> result =
CompletableFuture.allOf(usersResult.stream().toArray(CompletableFuture[]::new))
.thenApply(__ -> usersResult
.stream()
.map(CompletableFuture::join)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
我正在从数据库中读取pdf文件列表,对它们进行解析,并用它们执行一些任务 当我阅读这个pdf列表时,我发现从pdf中提取图像需要花费更多的时间,而且我不需要阻止我的主线程来阅读图像。所以我想在一个单独的线程中执行提取图像 我想从一个又一个pdf中读取图像,而不是一次将所有pdf加载到内存中(由于内存问题)。所以我只想要两条线;一个应该是主线程(从pdf中读取一些文本并执行其他操作),另一个应该是提
我有以下问题: 我有一个如下的方法,一次只能收集500个名字: 我有一个1000个名字的列表,因此我想使用番石榴将这个列表划分为最大大小为500的子列表 并将其传递给请求以获取结果DTO列表。如何在 Java8 中执行此操作?
我想通过调用来映射列表中的每个条目,它返回多个条目,然后将结果作为列表收集。 如果没有溪流,我会这样做: 我如何用流来完成这件事呢?这将给出一个编译错误:
在阅读了Oracle站点上的这篇文章https://community.Oracle.com/docs/doc-995305之后,我将尝试实现“Some Two-to-One selection patterns”段落中描述的模式。这最后一类模式还包含二对一模式。但是这次不是执行一次下游元素,而是完成两个上游元素,当两个上游元素中的一个完成时执行下游元素。例如,当我们要解析域名时,这可能会证明非常
问题内容: 我盯着一些命令性代码,试图将其转换为纯函数式样式。基本上有一个迭代的for循环,在该循环中,我检查3个谓词,并根据匹配的谓词填充3个谓词。输出集可以重叠。如何使用Java 8 Streams / map / filter /等以纯功能方式实现此目的? 问题答案: 最简单的解决方案(除了将所有内容保留为更容易之外)是创建三个单独的流: 如果有谓词列表,则可以创建相应的集合列表: 在此,结
我有两个资源和,我可以用检索用户的产品。这很简单,我会返回一个JSON响应,如下所示: 现在,如果我想同时获得和他们的,该怎么办?我知道我可以使用在调用并返回如下数据: 但这是最佳实践吗?还是退回这样的东西更好: 所以我的问题是: 在一次呼叫中返回多个数据收集的最佳实践是什么