8

Why

Predicate<? super Integer> isGreaterThanZero = num -> num.intValue() > 0;

works for

isGreaterThanZero.test( new Integer( 2 ));

and not

Predicate<? extends Number> isGreaterThanZero = num -> num.intValue() > 0;

I see them as the same since Integer is-a Number

1 Answers1

13

When you declare Predicate<? extends Number> isGreaterThanZero, you are telling the compiler that isGreaterThanZero is a Predicate parametrized by some unknown subtype of Number.

As far as the compiler knows, it could be a Predicate<Double> or a Predicate<BigInteger>. Can you safely pass an Integer to test(Double x) or to test(BigInteger x)? You cannot. The only thing that you can safely pass to test method of Predicate<? extends Number> is null.

If you want isGreaterThanZero to be a predicate that works on any subtype of Number, you should declare it as Predicate<Number>.

Misha
  • 27,433
  • 6
  • 62
  • 78
  • so it works for `super` since the Integer is found in the root of my generics? –  Jun 03 '16 at 03:14
  • if Number has only Integer as its subclass, will it work? Will java infer(if that's the right term) that Number has only one possible subclass? –  Jun 03 '16 at 03:16
  • 3
    It works for `super` because `Integer` is subtype of any class that satisfies wildcard `? super Number`. So whatever class the wildcard happens to represent, `Predicate super Number>` can *consume* an `Integer`. You may want to read through http://stackoverflow.com/q/2723397/3920048 for an in-depth explanation of these issues and the *PECS* mnemonic. – Misha Jun 03 '16 at 03:56
  • 3
    @fireflieslive For your second question, no, compiler wouldn't have let you do this if there were only one subtype of `Number`. What if you compile your code and tomorrow write a new subtype of `Number`? Now your compiled code is not type-safe. – Misha Jun 03 '16 at 03:58
  • 1
    @fireflieslive: even if you have a `Predicate extends Integer>` (note that `Integer` is `final`), you can’t pass an `Integer` to its `test` method. There is no guaranty that `Integer` will still be `final` and without subclasses at runtime. – Holger Jun 03 '16 at 08:14