Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Java chooses Object parameterized type when using generics with lambda?

Let's say I have method which takes a java.util.function.Predicate and return CompletableFuture:

public <R> CompletableFuture<R> call(Predicate<R> request) {
    return new CompletableFuture<>();
}

If I call this method using an anonymous class like this:

Integer a = call(new Predicate<Integer>() {
    @Override
    public boolean test(Integer o) {
        return false;
    }
}).join();

It works because I have to explicitly declare the type of the Predicate. However, if I use lambda expression instead of anonymous class like this:

Integer a = call(o -> false).join();

It doesn't compile because Java thinks that it's a Predicate<Object> and returns a message like this:

Error:(126, 42) java: incompatible types: java.lang.Object cannot be converted to java.lang.Integer

There are a few workarounds that I found. I may create the CompletableFuture variable explicitly instead of chaining, or add an unnecessary extra argument Class<R> that tells Java which type we want to get or force the type in lambda expression.

However I wonder why Java chooses Object instead of Integer in the first lambda example, it already knows which type I want to get so the compiler may use the most specific type instead of Object because all of the three workarounds seems ugly to me.

like image 785
burak emre Avatar asked Dec 05 '25 10:12

burak emre


1 Answers

There are limits to Java 8's type inference, and it does not look at the type of the variable that you assign the result to. Instead, it infers the type Object for the type parameter.

You can fix it by explicitly specifying the type of the argument o in the lambda:

Integer a = call((Integer o) -> false).join();
like image 126
Jesper Avatar answered Dec 07 '25 00:12

Jesper



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!