为什么编译器给我这不能从 CompletableFuture<Object> 转换为 CompletableFuture<String>

Why compiler in given me this cannot convert from CompletableFuture<Object> to CompletableFuture<String>

我正在尝试使用 CompletableFuture 链接一些文件处理程序,这应该是 return a 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() returns CompletableFuture<Void>,所以我在其 thenApply()...

中生成一个字符串

但为什么编译器假设我在这里生成 CompletableFuture<Object>

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

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

你的主要条款是

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

所以指定函数应该return一个String。但是你的代码试图 return 一个 CompletableFuture<String>,因为 Stream.of(gen1, gen2) .map(CompletableFuture::join) .collect(joining(",")) 产生一个 String 而你在 return CompletableFuture .allOf(gen1, gen2) .thenApply(r -> …);

中使用这个表达式

对于泛型代码中此类类型不匹配的情况,编译器错误消息通常毫无帮助。

最简单的修复(变化最小)是使用 thenCompose 而不是 thenAppy,允许函数 return a 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。后者的效率会稍微高一些,但由于它不太可能主导整体性能,所以这是一个品味问题。