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

标签 generics java-8 completable-future

我正在尝试使用 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/

相关文章:

java - 类的通用类型

c# - 为什么 IEqualityComparer<T> 不在 .NET 中扩展 IEqualityComparer

scala - 如何在Scala中多次继承通用特征?

java - 如何 toString() 像这样的列表 : List<Option>?

java - CompletableFuture 编写异常

java - 关于Java泛型函数,需要澄清

java - JAVA-8 中堆上的字符串对象数

java - 反序列化 JSon String int List<Map<String, Object>> 的正确方法

java - 关闭CompletableFuture链中的外部流程

java - 哪个ExecutorService最适合阻塞IO任务