6

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.

Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
daniel
  • 107
  • 6

4 Answers4

7

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 returns Predicate<T> (no matter what actual type of its input parameter is), so it returns Predicate<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 is Predicate<Object>).
Vadym Pechenoha
  • 574
  • 5
  • 17
3

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));
davidxxx
  • 125,838
  • 23
  • 214
  • 215
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
Pau Trepat
  • 697
  • 1
  • 6
  • 24
  • 4
    `It cast the Predicate to a Predicate if you don't type it.` well not exactly *casting*, but instead *inferring* – Lino May 03 '18 at 10:39
1

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));
Dorian Gray
  • 2,913
  • 1
  • 9
  • 25