我正在尝试使用 CompletableFuture 链接一些文件处理程序,它应该返回 CompletableFuture<String>
:
CompletableFuture<String> allGen = loadFile1().thenApply(params1 -> {
CompletableFuture<String> gen1 = loadFile2().thenApply(params2 -> {
return generateResultFile1(params1, params2);
});
CompletableFuture<String> gen2 = loadFile3().thenApply(params3 -> {
return generateResultFile2(params1, params3);
});
return CompletableFuture
.allOf(gen1, gen2)
.thenApply(r -> Stream.of(gen1, gen2).map(CompletableFuture::join).collect(joining(",")));
});
我知道CompletableFuture.allOf()
返回 CompletableFuture<Void>
,所以我在其 thenApply()
中生成了一个字符串...
但为什么编译器假设我正在生成一个 CompletableFuture<Object>
在这里?
请问我在这里遗漏了什么?
顺便说一句,像这样链接方法是更好的方法吗?
最佳答案
你的主要条款是
CompletableFuture<String> allGen = loadFile1().thenApply(params1 -> {
…
});
所以指定函数应该返回 String
.但是您的代码试图返回 CompletableFuture<String>
, 作为 Stream.of(gen1, gen2) .map(CompletableFuture::join) .collect(joining(","))
产生 String
你在 return CompletableFuture .allOf(gen1, gen2) .thenApply(r -> …);
中使用了这个表达式
在泛型代码中出现此类类型不匹配的情况下,编译器错误消息通常毫无帮助。
最简单的修复(变化最小)是使用 thenCompose
而不是 thenAppy
, 允许函数返回 CompletableFuture
.
CompletableFuture<String> allGen = loadFile1().thenCompose(params1 -> {
CompletableFuture<String> gen1 = loadFile2().thenApply(params2 -> {
return generateResultFile1(params1, params2);
});
CompletableFuture<String> gen2 = loadFile3().thenApply(params3 -> {
return generateResultFile2(params1, params3);
});
return CompletableFuture.allOf(gen1, gen2)
.thenApply(r -> Stream.of(gen1, gen2)
.map(CompletableFuture::join).collect(joining(",")));
});
但是,有机会使用简化的语法
CompletableFuture<String> allGen = loadFile1().thenCompose(params1 -> {
CompletableFuture<String> gen1 = loadFile2()
.thenApply(params2 -> generateResultFile1(params1, params2));
CompletableFuture<String> gen2 = loadFile3()
.thenApply(params3 -> generateResultFile2(params1, params3));
return CompletableFuture.allOf(gen1, gen2)
.thenApply(r -> Stream.of(gen1, gen2)
.map(CompletableFuture::join).collect(joining(",")));
});
如果代码总是恰好组合两个结果,您可以使用更简单的方法:
CompletableFuture<String> allGen = loadFile1().thenCompose(params1 ->
loadFile2().thenApply(params2 -> generateResultFile1(params1, params2))
.thenCombine(
loadFile3().thenApply(params3 -> generateResultFile2(params1, params3)),
(s1, s2) -> String.join(",", s1, s2))
);
尽管嵌套不同,loadFile2().thenApply(…)
和 loadFile3().thenApply(…)
仍然是两个独立的操作,只有最后的(s1, s2) -> String.join(",", s1, s2)
取决于两者。
如果你想让这个更明显,保留局部变量
CompletableFuture<String> allGen = loadFile1().thenCompose(params1 -> {
CompletableFuture<String> gen1
= loadFile2().thenApply(params2 -> generateResultFile1(params1, params2));
CompletableFuture<String> gen2
= loadFile3().thenApply(params3 -> generateResultFile2(params1, params3));
return gen1.thenCombine(gen2, (s1, s2) -> s1 + "," + s2);
});
如上例所示,您也可以替换 String.join(",", s1, s2)
与 s1 + "," + s2
这里。后者的效率会稍微高一些,但由于它不太可能主导整体性能,所以这更像是一个品味问题。
关于generics - 为什么编译器给我这不能从 CompletableFuture<Object> 转换为 CompletableFuture<String>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68996002/