Java Generic List<List<? extends Number>> - java

How come in java we cannot do:
List<List<? extends Number>> aList = new ArrayList<List<Number>>();
Even though this is OK:
List<? extends Number> aList = new ArrayList<Number>();
Compiler error message is:
Type mismatch: cannot convert from ArrayList<List<Number>> to List<List<? extends Number>>

In Java, if Car is a derived class of Vehicle, then we can treat all Cars as Vehicles; a Car is a Vehicle. However, a List of Cars is not also a List of Vehicles. We say that List<Car> is not covariant with List<Vehicle>.
Java requires you to explicitly tell it when you would like to use covariance and contravariance with wildcards, represented by the ? token. Take a look at where your problem happens:
List<List<? extends Number>> l = new ArrayList<List<Number>>();
// ---------------- ------
//
// "? extends Number" matched by "Number". Success!
The inner List<? extends Number> works because Number does indeed extend Number, so it matches "? extends Number". So far, so good. What's next?
List<List<? extends Number>> l = new ArrayList<List<Number>>();
// ---------------------- ------------
//
// "List<? extends Number>" not matched by "List<Number>". These are
// different types and covariance is not specified with a wildcard.
// Failure.
However, the combined inner type parameter List<? extends Number> is not matched by List<Number>; the types must be exactly identical. Another wildcard will tell Java that this combined type should also be covariant:
List<? extends List<? extends Number>> l = new ArrayList<List<Number>>();

I'm not very familiar with Java syntax but it seems that your issue is this:
Covariance & Contravariance

You should definitely use the ? type wildcard when appropriate, do not avoid it as a general rule. For example:
public void doThingWithList(List<List<? extends Number>> list);
allows you to pass a List<Integer> or a List<Long>.
public void doThingWithList(List<List<Number>> list);
allows you to only pass arguments declared as List<Number>. A small distinction, yes, but using the wildcard is powerful and safe. Contrary to how it may seem, a List<Integer> is not a subclass, or is not assignable, from List<Number>. Nor is List<Integer> a subclass of List<? extends Number, which is why the code above does not compile.

Your statement does not compile because List<? extends Number> is not the same type as List<Number>. The former is a supertype of the latter.
Have you tried this? Here I'm expressing that the List is covariant in its type argument, so it will accept any subtype of List<? extends Number> (which includes List<Number>).
List<? extends List<? extends Number>> aList = new ArrayList<List<Number>>();
Or even this. Here the type parameter for the ArrayList on the right-hand side is the same as the type parameter on the left-hand side, so variance is not an issue.
List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
You should be able to just say
List<List<Number>> aList = new ArrayList<List<Number>>();
I tend to avoid the ? type wildcard whenever possible. I find that the expense incurred in type annotation is not worth the benefit.

List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
aList.add(new ArrayList<Integer>());

Related

What is the point of stating that a type wildcard must extend Object? [duplicate]

I've seen the wildcard used before to mean any object - but recently saw a use of:
<? extends Object>
Since all objects extend Object, are these two usages synonymous?
<?> and <? extends Object> are synonymous, as you'd expect.
There are a few cases with generics where extends Object is not actually redundant. For example, <T extends Object & Foo> will cause T to become Object under erasure, whereas with <T extends Foo> it will become Foo under erasure. (This can matter if you're trying to retain compatibility with a pre-generics API that used Object.)
Source: http://download.oracle.com/javase/tutorial/extra/generics/convert.html; it explains why the JDK's java.util.Collections class has a method with this signature:
public static <T extends Object & Comparable<? super T>> T max(
Collection<? extends T> coll
)
Although <?> is supposed to be a shortcut for <? extend object>, there is a tiny difference between the two.
<?> is reifiable while <? extend object> is not. The reason they did this is to make it easier to distinguish reifiable type. Anything that looks like <? extends something>,<T>,<Integer> are nonreifiable.
For example, this code would work
List aList = new ArrayList<>();
boolean instanceTest = aList instanceof List<?>;
but this gives an error
List aList = new ArrayList<>();
boolean instancetest = aList instanceof List<? extends Object>;
for more info read Java generics and collections by Maurice Naftalin
<?> is a shorthand for <? extends Object>.
You may read below shared link for more details.
<?>
"?" denotes any unknown type, It can represent any Type at in code for. Use this wildcard if you are not sure about Type.
ArrayList<?> unknownList = new ArrayList<Number>(); //can accept of type Number
unknownList = new ArrayList<Float>(); //Float is of type Number
Note: <?> means anythings. So It can accept of Type which are not inherited from Object class.
<? extends Object>
<? extends Object> means you can pass an Object or a sub-class that extends Object class.
ArrayList<? extends Number> numberList = new ArrayList<Number>(); //Number of subclass
numberList = new ArrayList<Integer>(); //Integer extends Number
numberList = new ArrayList<Float>(); // Float extends Number
T – used to denote type
E – used to denote element
K – keys
V - values
N – for numbersRef:

Why ListList<? super E> is List<? extends List<? super E>> but not List<List<? super E>>

I have a generic interface interface ListList<E> extends List<List<E>>. For some reasons, I can't cast ListList<? super T> to List<List<? super T>>. Is there any way of doing it and why it doesn't work?
By this moment I've already tried the following:
Simple assignment, this way I've managed to assign ListList<? super T> to List<? extends List<? super T>> (1), but when I try to assign ListList<? super T> to List<List<? super T>> I get Incompatible types compile-time error (1.1).
Explicit type conversion, it doesn't work because of the same Incompatible types compile-time error (2).
Casting to raw type ListList, it works (3), but I don't like raw types.
Adding all elements from ListList<? super T> to List<? extends List<? super T>>, it works (4), but I need a more general solution which works not only with ListList<E>, but with any generic type.
Here is my code:
ListList<? super T> var = new ArrayListList<>();
List<? extends List<? super T>> work = var; // (1)
List<List<? super T>> notWork = var; // (1.1)
List<List<? super T>> explicit = (List<List<? super T>>) var; // (2)
List<List<? super T>> raw = (ListList) var; // (3)
List<List<? super T>> copy = new ArrayList<>(); // (4)
copy.addAll(var); // (4)
I've expected ListList<? super T> to be List<List<? super T>>, but it appeared to be List<? extends List<? super T>>. I need to know why it is and how I can cast it to List<List<? super T>> without raw types and copying of elements.
At first, it looks like these assignments should all succeed, but they don't because of the inner wildcard ? super T. If we remove those wildcards, then all the assignments compile.
public static <T> void test() {
ListList<T> var = new ArrayListList<>();
List<? extends List<T>> work = var; // Compiles
List<List<T>> notWork = var; // Compiles
List<List<T>> explicit = (List<List<T>>) var; // Compiles
List<List<T>> raw = (ListList) var; // Compiles with warning
List<List<T>> copy = new ArrayList<>(); // Compiles
copy.addAll(var); // Compiles
}
I still get the unchecked conversion warning for (3), but they all still compile.
At first glance it looks like declaring the interface
ListList<E> extends List<List<E>>
makes a ListList equivalent to a List of Lists. However what you have done is take a nested type parameter and made it the main type parameter. The reason that that makes a difference is nested wildcards don't perform wildcard capture.
A nested wildcard here means "a list of lists of any type matching the bound", but a main-level wildcard here means "a 'listlist' of a specific yet unknown type matching the bound".
One cannot add an object that is a supertype of the lower bound to a collection, because the type parameter -- a specific yet unknown type -- may be the actual bound.
List<? super Integer> test2 = new ArrayList<>();
test2.add(2); // Compiles; can add 2 if type parameter is Integer, Number, or Object
test2.add((Number) 2); // Error - Can't add Number to what could be Integer
test2.add(new Object()); // Error - Can't add Object to what could be Integer
Because Java's generics are invariant, the types must match exactly when type parameters are involved, so similar cases for ListList all fail to compile.
// My assumption of how your ArrayListList is defined.
class ArrayListList<E> extends ArrayList<List<E>> implements ListList<E> {}
ListList<? super Integer> llOfSuperI = new ArrayListList<>();
llOfSuperI.add(new ArrayList<Integer>()); // capture fails to match Integer
llOfSuperI.add(new ArrayList<Number>()); // capture fails to match Number
llOfSuperI.add(new ArrayList<Object>()); // capture fails to match Object
However, a List of List compiles with all 3 cases.
List<List<? super Integer>> lOfLOfSuperI = new ArrayList<>();
lOfLOfSuperI.add(new ArrayList<Integer>()); // no capture; compiles
lOfLOfSuperI.add(new ArrayList<Number>()); // no capture; compiles
lOfLOfSuperI.add(new ArrayList<Object>()); // no capture; compiles
Your ListList is a different type than a List of Lists, but the differing generics behavior of where the type parameter is defined means that there is different generics behavior. This is why you cannot directly assign a ListList<? super T> to a List<List<? super T>> (1.1), and also why you can't cast it (2). You can cast to a raw type to get it to compile (3), but that introduces the possibilities of ClassCastException in future use of the casted object; that is what the warning is about. You can assign it to a List<? extends List<? super T>> (1), introducing another wildcard to capture a subtype relationship, but that introduces a wildcard to be captured; you won't be able to add anything useful to that list.
These differences have arisen only because a wildcard introduces wildcard capture and the associated differences. Without using a wildcard, a ListList<E> is equivalent to a List<List<E>> and as shown at the top of this answer, shows no problems compiling the code.
If you want all of your sub-lists to use the same exact type parameter, then go ahead and use your ListList interface, but don't use any wildcards. This forces the exact same type parameter for all lists that are added to your ListList, i.e. a ListList<Integer> can only hold List<Integer>s.
If you want all of your sub-lists to simply match a wildcard, e.g. contain a List<Number>, List<Integer>, and List<Object> in the same list, then just use a List<List<? super T>> to avoid wildcard capture.

Java - Is "extends Object" really necessary on some Collections method specifications? [duplicate]

I've seen the wildcard used before to mean any object - but recently saw a use of:
<? extends Object>
Since all objects extend Object, are these two usages synonymous?
<?> and <? extends Object> are synonymous, as you'd expect.
There are a few cases with generics where extends Object is not actually redundant. For example, <T extends Object & Foo> will cause T to become Object under erasure, whereas with <T extends Foo> it will become Foo under erasure. (This can matter if you're trying to retain compatibility with a pre-generics API that used Object.)
Source: http://download.oracle.com/javase/tutorial/extra/generics/convert.html; it explains why the JDK's java.util.Collections class has a method with this signature:
public static <T extends Object & Comparable<? super T>> T max(
Collection<? extends T> coll
)
Although <?> is supposed to be a shortcut for <? extend object>, there is a tiny difference between the two.
<?> is reifiable while <? extend object> is not. The reason they did this is to make it easier to distinguish reifiable type. Anything that looks like <? extends something>,<T>,<Integer> are nonreifiable.
For example, this code would work
List aList = new ArrayList<>();
boolean instanceTest = aList instanceof List<?>;
but this gives an error
List aList = new ArrayList<>();
boolean instancetest = aList instanceof List<? extends Object>;
for more info read Java generics and collections by Maurice Naftalin
<?> is a shorthand for <? extends Object>.
You may read below shared link for more details.
<?>
"?" denotes any unknown type, It can represent any Type at in code for. Use this wildcard if you are not sure about Type.
ArrayList<?> unknownList = new ArrayList<Number>(); //can accept of type Number
unknownList = new ArrayList<Float>(); //Float is of type Number
Note: <?> means anythings. So It can accept of Type which are not inherited from Object class.
<? extends Object>
<? extends Object> means you can pass an Object or a sub-class that extends Object class.
ArrayList<? extends Number> numberList = new ArrayList<Number>(); //Number of subclass
numberList = new ArrayList<Integer>(); //Integer extends Number
numberList = new ArrayList<Float>(); // Float extends Number
T – used to denote type
E – used to denote element
K – keys
V - values
N – for numbersRef:

Using addAll() on List<? extends E> a and b doesn't work

Why doesn't this compile?
List<? extends Number> a = new ArrayList<>();
List<? extends Number> b = new ArrayList<>();
a.addAll(b);
Because it wouldn't be safe.
List<? extends Number> should be read as some list where the element type extends Number. So in runtime a could be a List<Long> and b could be a List<BigInteger>. In that case, a.addAll(b) would mean "add all BigIntegers to the list of Longs" which, if allowed, obviously wouldn't be type safe.
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Iterables.html
What really worked for me was Guava:
com.google.common.collect.Iterables.concat(...)
List<? extends Number> means
Items in this List have all the same class. Not only do they extend
Number, but are all the same type.
Due to type erasure during compile, the byte code interpreter does not know (and cannot infer), whether the ? of a and the ? refer to the same class.

Fancy generics capture collision

Please give me a hint as to what is going on here:
List<? extends Number> a = new ArrayList<Number>();
List<? extends Number> b = new ArrayList<Number>();
a.addAll(b); // ouch! compiler yells at me, see the block below:
/*
incompatible types
found : java.util.List<capture#714 of ? extends java.lang.Number>
required: java.util.List<java.lang.Number>
*/
This simple code does not compile. I vaguely remember something related to type captures, like those should be mostly used in interface specs, not the actual code, but I never got dumbfounded like that.
This of course might be fixed brute-forcefully, like that:
List<? extends Number> a = new ArrayList<Number>();
List<? extends Number> b = new ArrayList<Number>();
#SuppressWarnings({"unchecked"})
List<Number> aPlain = (List<Number>) a;
#SuppressWarnings({"unchecked"})
List<Number> bPlain = (List<Number>) b;
aPlain.addAll(bPlain);
So, do I really have to either give up captures in the declaration (the capture came to me from an interface, so I'll have to change some API), or stick with type casts with suppression annotations (which generally suck and complicates code a bit)?
You have essentially two lists of possibly different types. Because ? extends Number means a class which extends Number. So for list a it can be classA and for list b it can be for example classB. They are not compatible, they can be totally different.
The problem is that if you use List<? extends Number> you could actually do:
List<? extends Number> a = new ArrayList<Integer>();
List<? extends Number> b = new ArrayList<Double>();
a.addAll(b); //ouch, would add Doubles to an Integer list
The compiler can't tell from List<? extends Number> what the actual type parameter is and thus won't let you do the add operation.
You also shouldn't cast the lists to List<Number> if you get them as a parameter, since you could actually have a list of Integer objects and add Double objects to it.
In that case you better create a new List<Number> and add the objects from both lists:
List<Number> c = new ArrayList<Number>(a.size() + b.size());
c.addAll(a);
c.addAll(b);
Edit: in case you create both lists locally, you would not neet the ? wildcard anyway (since you'd always have List<Number>).
PECS (producer-extends, consumer-super)
You cannot put anything into a type declared with an EXTENDS wildcard
except for the value null, which belongs to every reference type
You cannot get anything out from a type declared with an SUPER
wildcard except for a value of type Object, which is a super type
of every reference type
Don't use the ? wildcard. It means "Some specific type I don't know", and since you don't know the type, you can't add anything to the list. Change your code to use List<Number> and everything will work.
This is fast becoming the most frequently asked Java question, in a hundred variations...
The thing is:
List<? extends Number> a = new ArrayList<Number>();
List<? extends Number> b = new ArrayList<Number>();
could also be read as:
List<x extends Number> a = new ArrayList<Number>();
List<y extends Number> b = new ArrayList<Number>();
How should the compiler know that x and y are the same?

Categories

Resources