Home > front end >  Why compiler in given me this cannot convert from CompletableFuture<Object> to CompletableFutu
Why compiler in given me this cannot convert from CompletableFuture<Object> to CompletableFutu

Time:09-17

I'm trying to chain some file handling procedures using CompletableFuture, that is supposed to 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(",")));
});

I know that CompletableFuture.allOf() returns CompletableFuture<Void>, so I'm generating a string in its thenApply()...

But why is the compiler is assuming that I'm producing a CompletableFuture<Object> here ?

What am I missing here, please?

Btw, it is a better way to chain methods like this?

CodePudding user response:

Your main clause is

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

So the specified function is supposed to return a String. But your code is trying to return a CompletableFuture<String>, as Stream.of(gen1, gen2) .map(CompletableFuture::join) .collect(joining(",")) produces a String and you’re using this expression in return CompletableFuture .allOf(gen1, gen2) .thenApply(r -> …);

The compiler error messages are often very unhelpful in cases of such type mismatches in generic code.

The simplest fix (with the smallest change) is to use thenCompose instead of thenAppy, allowing the function to 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(",")));
});

There are, however, opportunities to use simplified syntax

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(",")));
});

If the code is always combining exactly two results, you can use the even simpler:

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))
);

Despite the different nesting, loadFile2().thenApply(…) and loadFile3().thenApply(…) are still two independent operations and only the final (s1, s2) -> String.join(",", s1, s2) depends on both.

If you want to make this more obvious, keep the local variables

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);
});

As shown in the last example, you may also replace String.join(",", s1, s2) with s1 "," s2 here. The latter will be slightly more efficient, but since it’s rather unlikely to dominate the overall performance, it’s rather a matter of taste.

  • Related