【问题标题】:Why compiler in given me this cannot convert from CompletableFuture<Object> to CompletableFuture<String>为什么给定我的编译器无法从 CompletableFuture<Object> 转换为 CompletableFuture<String>
【发布时间】:2021-08-31 09:14:12
【问题描述】:

我正在尝试使用 CompletableFuture 链接一些文件处理过程,它应该返回 CompletableFuture&lt;String&gt;

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&lt;Void&gt;,所以我在它的thenApply() 中生成一个字符串...

但是为什么编译器会假设我在这里生成 CompletableFuture&lt;Object&gt; 呢?

请问我在这里遗漏了什么?

顺便说一句,这样链接方法更好吗?

【问题讨论】:

    标签: generics java-8 completable-future


    【解决方案1】:

    你的主要子句是

    CompletableFuture<String> allGen = loadFile1().thenApply(params1 -> {
        …
    });
    

    所以指定的函数应该返回一个String。但是你的代码试图返回一个CompletableFuture&lt;String&gt;,因为Stream.of(gen1, gen2) .map(CompletableFuture::join) .collect(joining(",")) 产生一个String,而你在return CompletableFuture .allOf(gen1, gen2) .thenApply(r -&gt; …); 中使用了这个表达式

    在泛型代码中出现此类类型不匹配的情况下,编译器错误消息通常非常无用。

    最简单的解决方法(更改最小)是使用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) -&gt; 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。后者的效率会稍高一些,但由于它不太可能主导整体性能,所以这只是一个品味问题。

    【讨论】:

    • 非常感谢 ;) 关于您最近的改进:gen1.thenCombine(gen2 是否会使这些 gen1 和 gen2 并行/同时运行?
    • allOf 一样,这对它们的完成完全没有影响。 loadFile2()loadFile3() 方法以及它们创建期货的方式决定了它们将如何完成。 allOfthenCombine 两种方法(以及所有其他链式操作)仅创建一个新的未来,该未来将在传入的期货完成后完成。如果您想确保generateResultFile1generateResultFile2 在每种情况下都并行运行,则必须将thenApply 替换为thenApplyAsync
    • 啊,好的。我现在明白了。两种生成方法都有return CompletableFuture.supplyAsync()。我将在它们上添加一个日志,以查看正在使用哪些线程来执行它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    相关资源
    最近更新 更多