Search code examples
javagenericswildcardbounded-wildcard

Is there an actual practical usecase of the wildcard character (?) in Java?


I don't get the actual practical use case of the wildcard character ? in Java, when using it with extends or super.

The official Oracle Java documentation shows an example of adding numbers to a list and sum them up:

private static double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number number : list) {
        sum += number.doubleValue();
    }
    return sum;
}

From my understanding List<? extends Number> list does not mean "a list of instances of Number objects and objects of possible sub-classes of Number" but instead "a list of objects of a single type, which have to be or extend the type Number". That's all fine.

Until I tried this code:

List<Number> numberList = new ArrayList<Number>();
numberList.add(Integer.valueOf(123));
numberList.add(Double.valueOf(2.34));
numberList.add(Float.valueOf(3.45f));

The instances can be added to the Number list through an implicit upcast to number references. And that list of numbers can then be used with the sumOfList method as shown above. But the elements would not be of a single type. So why would anyone use extends with ? anyways?

The other thing that I am not getting is the use of the wildcard character with super. It is fine, that you can define the lower bound of a type. The offical Oracle documentation shows this example:

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

Thing is, this works great for a simple thing like adding numbers to a list. But the code shown also works with lists like this:

List<Object> list = new ArrayList<Object>();
list.add(Integer.valueOf(123));
list.add(Double.valueOf(2.34));
list.add(new Person("John", "Doe"));

So as long as one would call methods, that would do anything useful with actual numbers like - I dunno - arithmetical operations the code would probably work fine. But when it comes to the John Doe entry, code meant for numbers would fail.

So can anyone clarify the actual practical use of the extends and super keywords in combination with the ? operator?


Solution

  • So why would anyone use extends with ? anyways?

    Because you may not have a List<Number> to pass to it. For example, you can pass a List<Integer>, a List<BigInteger> etc to sumOfList.

    If you hadn't declared it as accepting a List<? extends Number>, but instead as accepting a List<Number>, you could only pass a List<Number> to it - List<Integer> isn't a subtype of List<Number>.


    In terms of the addNumbers method: you simply need some kind of List to which it is safe to add instances of Integer (or subtypes [of which there are none, because it is final], or null).

    That's all List<? super Integer> means: it's safe to add instances of Integer to that.

    It's safe to pass a List<Object> to that method, because all Integers are Objects, so it's safe to add Integers to that list.

    Again, if you'd declared the method as accepting a List<Object> (or a List<Integer>), that would be all you could pass to it: a List<Object> (or a List<Integer>, respectively). You couldn't pass it, say, a List<Number>.


    So can anyone clarify the actual practical use of the extends and super keywords in combination with the ? operator?

    The practical use of wildcards is to increase the flexibility of API methods, as illustrated above: it allows you to declare a single method that takes a range of related types as inputs.

    You can also use wildcards in outputs, but this should be avoided, because the wildcard ends up in the type of the value at the call site, and just generally hangs around looking messy and confusing.