What is the difference between both these ways of lambda creation? Why doesn't the first one compile?
Predicate<Integer> predicate = Predicate.isEqual(0).or(Predicate.isEqual(1));
Gives:
error: incompatible types: Predicate<Object>
cannot be converted to Predicate<Integer> = Predicate.isEqual(0).or(Predicate.isEqual(1));
Predicate<Integer> pred21 = Predicate.isEqual(0);
Predicate<Integer> pred22 = pred21.or(Predicate.isEqual(1));
This one works.
Adding <Integer>
before the isEqual
method call should help :
Predicate<Integer> predicate = Predicate.<Integer>isEqual(0).or(Predicate.isEqual(1));
The reason behind such compiler behavior:
isEqual
is a static generic method which returnsPredicate<T>
(no matter what actual type of its input parameter is), so it returnsPredicate<Object>
when calling the method without specifying returning type explicitly.or
is also a static generic method, but it returns a predicate parametrized by the same type, as its input parameter (which isPredicate<Object>
).
The problem is related to the way which the inference works in Java : it depends on the target.
Here :
Predicate<Integer> predicate = Predicate.isEqual(0)
.or(Predicate.isEqual(1));
The type returned by or(Predicate.isEqual(1))
depends on the type returned by Predicate.isEqual(0)
(the nearest target) but this invocation doesn't specify any other type as return.
So Object
is returned by or(Predicate.isEqual(1))
as the method isEqual()
defines T
as return type without any wildcard :
static <T> Predicate<T> isEqual(Object targetRef) {
To solve your issue you indeed need to specify the return type of the first invocation in order to allow the chained invocation to infer the correct type : Integer
.
Predicate<Integer> predicate = Predicate.<Integer>isEqual(0)
.or(Predicate.isEqual(1));
This happens because
Predicate.isEqual(0)
has this signature:
static <T> Predicate<T> isEqual(Object targetRef)
It infer Predicate<Object>
if you don't type it.
To type it you can type the return type
Predicate<Integer> pred21 = Predicate.isEqual(0);
Or type the call like
Preicate.<Integer>isEqual
Look at the signature:
static <T> Predicate<T> isEqual(Object targetRef)
In the first example, the compiler cannot guess the generic type parameter, so it returns a Predicate<Object>
.
The correct way to type it in one line would be to specify the type parameter like
Predicate<Integer> predicate = Predicate.<Integer>isEqual(0).or(Predicate.isEqual(1));
来源:https://stackoverflow.com/questions/50152693/lambda-as-a-combination-of-methods-from-the-predicate-interface-doesnt-compile