Java 8 CompletableFuture returning a subtype from the declaration

544 views Asked by At

Sorry for the poor title, if someone has a better idea I'm open to suggestion.

I was playing around with the CompletableFuture and I stumbled upon something strange.

Let's say you have 2 classes: A and B where B extends A, so B is a subtype of A.

Now, let's declare a CompletableFuture:

CompletableFuture<A> promiseofA = CompletableFuture.supplyAsync(() -> new B());

This is working because B being a subtype of A it conforms to the declaration of the CompletableFuture. Now, if I want to add a exceptionally step, then I have a compiling exception:

CompletableFuture<A> promiseOfA = CompletableFuture.supplyAsync(() -> new B())
                                                   .exceptionally(ex -> new B());

In this case Java is complaining, stating that:

Compilation error[ java.util.concurrent.CompletableFuture<B> cannot be converted to java.util.concurrent.CompletableFuture<A>]

Why is it working without the excepionally step and not with it?

2

There are 2 answers

1
Kiskae On BEST ANSWER

It does not work when you add exceptionally because it is completely dependant on the source future for its typing.

This means that for exceptionally it sees that the source future is CompletableFuture<B>, then the type it returns MUST be CompletableFuture<B>.

If you specify that the source is actually CompletableFuture<A> (CompletableFuture.<A>supplyAsync(...)) then it will correctly compile again. It is a problem with the generic type deduction in Java.

3
KayV On

I added wildcard which extends A with exceptionally, and the compilation error was gone:

CompletableFuture<? extends A> promiseOfA1 = CompletableFuture.supplyAsync(() -> new B())
            .exceptionally(ex -> new B());