2

I thought that parameter and wildcard placeholder roughly has same meaning, where the first one is for defining classes and methods and the second is for declaring variables. But apparently it is not the case.

import java.util.List;
import java.util.function.Consumer;

public class Main {

    public static void main(String[] args) {
        Consumer<List<? extends Number>> l1 = null;
        Consumer<List<? extends Number>> l2 = null;

        l1 = l2;    // compiles
    }

    static <T extends Number> void m(Consumer<List<T>> l) {
        Consumer<List<? extends Number>> l3 = l; // doesn't compile
    }
}

I thought that line Consumer<List<? extends Number>> l3 = l should work just as l1 = l2;. But it is not the case. Can someone explain why this sample doesn't compile and how can I workaround this.

Artem Petrov
  • 772
  • 4
  • 17

1 Answers1

0

Consumer<List<T>> is not a subtype of Consumer<List<? extends Number>> even though List<T> is a subtype of List<? extends Number>, in the same way that Foo<Dog> is not a subtype of Foo<Animal> even though Dog is a subtype of Animal.

Generic type parameters are invariant, meaning that (unless you have a wildcard at the top level) they must match exactly. If you want it to be compatible with different type parameters, you must have a wildcard at the top level, like this:

Consumer<? extends List<? extends Number>> l3 = l;

Or you can just declare your method as

static void m(Consumer<? extends List<? extends Number>> l3)

and it will accept all the arguments that it accepted before.

(However, I want to point out that your method as declared with Consumer doesn't really make any sense. Your method is generic on T, and it takes in a consumer which takes in a List<T>. There is almost no way for your method to use this consumer, because your method would have to pass it a List<T>, but your method has no idea what T is, and it has no other arguments of type T or any other way to figure out what T is or get a List<T>, so the only thing it can safely pass in is an empty list. So the only way your method can use this consumer is to pass it an empty list, which is probably not very useful.)

newacct
  • 119,665
  • 29
  • 163
  • 224