-1

Why can't we pass List<X> to a function which has List<superclass of X>? For a normal variable this is possible.

Consider the MWE below. Why can we pass Integer to a function with a Number argument, and can't we not pass List<Integer> to List<Number>?

Questions:

  • How can I efficiently/nicely (so without constructing a new List) work around this?
  • What is the rationale of this language design decision?

MWE:

import java.util.ArrayList;
import java.util.List;

public class Tester {
    public static void main(String[] args) {
        Integer i = new Integer(2);
        // This works fine.
        processNumber(i);
        List<Integer> l = new ArrayList<Integer>();
        // ERROR "The method processNumberList(List<Number>) in the type 
        // Tester is not applicable for the arguments (List<Integer>)"
        processNumberList(l);   
    }
    private static void processNumber(Number n) {
    }
    private static void processNumberList(List<Number> l) { 
    }
}
robert
  • 1,921
  • 2
  • 17
  • 27
  • Because your function might try to put non-Integer numbers into the list. – Mad Physicist Aug 23 '16 at 18:04
  • The key thing to understand (the second answer in the duplicated link) - is that java generics are **invariant**; not **covariant**. And when you dig deeper, you will find that Java arrays are in fact **covariant**; and that has some good side, but it leads to **a lot** of problems. Therefore the java fathers decides to not repeat this "mistake" when adding generics. – GhostCat Aug 23 '16 at 18:31
  • `public void thisWouldBeEvil(List list) { list.add(Double.valueOf(Math.PI)); }` `thisWouldBeEvil(myListOfIntegers);` now pi is in your list of integers. – Louis Wasserman Aug 23 '16 at 19:11

2 Answers2

2

Replace your declaration with this:

private static void processNumberList(List<? extends Number> l) {...}
Beri
  • 11,470
  • 4
  • 35
  • 57
  • Aha, yes I already found out. But now I am wondering what is the difference between Beri approach and Nicolas approach below? – robert Aug 23 '16 at 18:16
  • This approach says "give me a list of anything that extends `Number`". The approach below says "for any given type `T` that extends `Number`, give me a list of type `T`. As long as you don't use the type-bound parameter anywhere else, there is no difference, however, if you need to ensure that, for example, between two different parameters the type is the same (or, say, you would want to *return* a list of the same `Number`-extending type), then you would have to use the approach below. – Piotr Wilkin Aug 23 '16 at 18:19
1

How can I efficiently/nicely (so without constructing a new List) work around this?

Simply change the signature of your method as next:

private static <T extends Number> void processNumberList(List<T> l) {
}
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • Why is this "T extends Number" placed before the void? When was this language construct introduced? What is the difference between this construct and (List l) – robert Aug 23 '16 at 18:11
  • It's a type-parametrized method. You can have methods (as opposed to classes) that are type parametrized. – Piotr Wilkin Aug 23 '16 at 18:12
  • I think this " void" is misleading because it can give an indication about the return type (which is void). Why is this construct introduced? – robert Aug 23 '16 at 18:13
  • @robert - Well the latter doesn't compile :/ – Oliver Charlesworth Aug 23 '16 at 18:13
  • Sorry I mean: List extends Number>. This does compile. So what is the difference between Nicolas construct and "private static void processNumber(List extends Number> l)"? Which to use when? This looks to me much cleaner. – robert Aug 23 '16 at 18:15
  • 1
    When you need type-bound parameters? Let's imagine you have an utility function to copy elements between lists of the same type. It's `private static void copyElements(List> x, List> y)`. But you want to ensure that both lists are of the same type. Generic methods are used for that - you can have a signature `private static void copyElements(List x, List y)`. – Piotr Wilkin Aug 23 '16 at 18:17
  • Thanks guys for your quick answer. – robert Aug 23 '16 at 18:19