Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 766
Cristiano Avatar asked Dec 17 '25 14:12

Cristiano


1 Answers

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.

like image 155
Holger Avatar answered Dec 20 '25 12:12

Holger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!