Please explain this generic code wildcard compile time error:
//no compile time error.
List<? extends Number> x = new ArrayList<>();
//compile time error.
List<? extends Number> x = new ArrayList<? extends Number>();
It's invalid syntax to instantiate a generic type with wildcards. The type List<? extends Number> means a List of some type that is or extends Number. To create an instance of this type doesn't make sense, because with instantiation you're creating something specific:
new ArrayList<? extends Number>();//compiler:"Wait, what am I creating exactly?"
Generic types with wildcards only make sense for variables and method parameters, because this allows greater freedom in what can be assigned/passed into them.
//compiler:"Okay, so passing in a List<Integer> or a List<Double> are both fine"
public void eatSomeNumbers(List<? extends Number> numbers) {
for (Number number : numbers) {
System.out.println("om nom " + number + " nom");
}
}
Make sure to keep in mind the limitations that come with using wildcards.
List<? extends Number> numList = ...
numList.add(new Integer(3));//compiler:"Nope, cause that might be a List<Double>"
As for your first example, the diamond is a new feature in Java 7 that allows the compiler to infer the type of the new generic instance, based on the type of the variable it's assigned to. In this case:
List<? extends Number> x = new ArrayList<>();
The compiler is most likely inferring new ArrayList<Number>() here, but what's inferred hardly matters, as long as it's a valid assignment to the given variable. This was the reason for the diamond operator being introduced - that specifying the generic type of a new object was redundant, as long some generic type would make it a valid assignment/argument.
This reasoning only makes sense if you remember that generics in Java are a purely compile-time language feature, because of type erasure, and have no meaning at runtime. Wildcards exist only because of this limitation. By contrast, in C# generic type information sticks around at runtime - and generic wildcards don't exist in that language.
Use
List<? extends Number> x = new ArrayList<Number>();
instead.
Related
The recurring explanation I find is that an upper bounded wildcard relaxes the restrictions of types that a type parameter can accept. This concept applies to bounded generics as well, for example:
static <T extends Number> void gMethod (ArrayList <T> list) {}
This method's generic will accept Objects of type Number or any of it's sub classes when specified:
ArrayList <Integer> intList = new ArrayList();
gMethod(intList); // allowed
For further elaboration that a generic bounded to Number will accept type arguments of Number or any of it's sub classes as well:
class Thing <T extends Number> {}
Thing <Number> numThing = new Thing();
Thing <Integer> intThing = new Thing();
Thing <Double> dubThing = new Thing(); // All three instances work
Given this, the only benefit I can see to using an upper bounded wildcard vs a bounded generic is that an upper bounded wildcard type argument can be declared without relying on a type parameter already declared by either a class or method. Is there a more important benefit that I'm missing?
„…the only benefit I can see to using an upper bounded wildcard vs a bounded generic…“
If your use case only ever calls for you working with one Thing at a time, then the simple usage scenario you outline is all you'll ever need.
But eventually you'll have a use case where you will need to work with a heterogeneous assortment of Things. That's when you'll need to pull slightly more advanced polymorphism out from your toolbox.
„…Is there a more important benefit that I'm missing?…“
One super important benefit that it sounds like you're missing is a substitutability relationship between types; called covariance.
For example, since it's legal to do this:
Integer[] intAry = {2,4,6,8};
Number[] numAry = intAry;
Then intuitively, it seems like you should be able to do this:
List<Integer> intList = List.of(8,6,7,5,3,0,9);
List<Number> numList = intList; // but this fails to compile
A wildcard with an upper bound effectively makes collections covariant:
List <? extends Number> numList = intList;
Since Integer extends Number :
Thing<Number> numThing = new Thing<>();
Thing<Integer> intThing = new Thing<>();
Then intuitively, it seems like you should be able to do this:
numThing = intThing; // but this fails to compile
A wildcard with an upper bound effectively makes Things more intuitive:
Thing<? extends Number> numThing = new Thing<>();
numThing = intThing; /* That makes sense! */
Same deal with methods. With this declaration:
public static void use(Thing<Number> oneThing){
/*...*/
}
This would fail to compile:
Thing<Integer> intThing = new Thing<>();
use(intThing); /* error: no suitable method found for use(Thing<Integer>) */
Wild cards with upper bounds makes it possible to use Things the way you intuitively would think they'd be used:
public static void use(Thing<? extends Number> anyThing){
/* ...*/
}
...
Thing<Integer> intThing = new Thing<>();
use(intThing); /* Perfectly fine! */
„…applies to bounded generics…This method's generic will accept…an upper bounded wildcard vs a bounded generic…“
The things you've incorrectly called „generics“ are actually called either type parameters, type variables or type arguments; depending on the context.
I have two classes with nested generics. Is there a way to get rid of the
Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>> error ?
In the last assignment
public class Value<V> {
V val;
public Value(V val) {
this.val = val;
}
#Override
public String toString() {
return "" + val;
}
}
public class Msg<T> {
T holder;
public Msg( T holder) {
this.holder = holder ;
}
public String toString() {
return "" + holder;
}
public static void main(String[] args) {
Msg<Value<String>>strMsg = new Msg(new Value<String>("abc"));
// This is OK
Msg<?>objMsg = strMsg;
// Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>>
Msg<Value<?>>objMsg = strMsg;
}
}
Use the following:
Msg<? extends Value<?>> someMsg = strMsg;
The problem is that the ? in Msg<Value<?>> objMsg is NOT capable of capture conversion. It's not "a Msg of Value of some type. It's "a Msg of Value of ANY type".
This also explains why along with the declaration change, I've also renamed the variable to someMsg. The Value can't just be any Object. It must belong to some type (String in this example).
A more generic example
Let's consider a more generic example of a List<List<?>>. Analogously to the original scenario, a List<List<?>> can NOT capture-convert a List<List<Integer>>.
List<List<Integer>> lolInt = null;
List<List<?>> lolAnything = lolInt; // DOES NOT COMPILE!!!
// a list of "lists of anything"
List<? extends List<?>> lolSomething = lolInt; // compiles fine!
// a list of "lists of something"
Here's another way to look at it:
Java generics is type invariant
There's a conversion from Integer to Number, but a List<Integer> is not a List<Number>
Similarly, a List<Integer> can be capture-converted by a List<?>, but a List<List<Integer>> is not a List<List<?>>
Using bounded wildcard, a List<? extends Number> can capture-convert a List<Integer>
Similarly, a List<? extends List<?>> can capture-convert a List<List<Integer>>
The fact that some ? can capture and others can't also explains the following snippet:
List<List<?>> lolAnything = new ArrayList<List<?>>(); // compiles fine!
List<?> listSomething = new ArrayList<?>(); // DOES NOT COMPILE!!!
// cannot instantiate wildcard type with new!
Related questions
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
Very long and detailed exploration into this problem
Java Generic List<List<? extends Number>>
Any simple way to explain why I cannot do List<Animal> animals = new ArrayList<Dog>()?
What is the difference between <E extends Number> and <Number>?
See also
Java Generics Tutorial
Generics and Subtyping | Wildcards | More Fun with Wildcards
Angelika Langer's Java Generics FAQ
What is a bounded wildcard?
Which super-subtype relationships exist among instantiations of generic types?
My answer is similar to another, but hopefully is more clear.
List<List<?>> is a list of (lists of anything).
List<List<String>> is a list of (lists of strings).
The latter cannot be converted to the former because doing so would allow you to add a List<Number> to your List<List<String>>, which would clearly be broken.
Note that the rules for this don't change if you replace List with some type that doesn't have .add. Java would need declaration-site covariance and/or contravariance for that (like C#'s IEnumerable<out T> or Scala's List[+A]). Java only has use-site covariance and contravariance (? extends X, ? super X).
Although your generic type parameter contains a wildcard, it is not itself a wildcard. When assigning to a variable (Msg<T>) with a non-wildcard generic type T, the object being assigned must have exactly T as its generic type (including all generic type parameters of T, wildcard and non-wildcard). In your case T is Value<String>, which is not the same type as Value<?>.
What you can do, because Value<String> is assignable to Value<?>, is use the wildcard type:
Msg<? extends Value<?>> a = new Msg<Value<String>>();
Not a direct answer but i strongly recommend the reading of: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf to better understand generics.
ILMTitan has a good solution, and if you don't want to make the class specific to Value you may as well use the base type instead of generics at this point because you'll be turning off a safety feature, but there is a way. You might even be able to pass a parameter to make this method more generic, but the key is "#SuppressWarnings".
#SuppressWarnings("unchecked")
Msg<Value<?>> convert()
{
return (Msg<Value<?>>) this;
}
This question already has an answer here:
Capturing wildcards in Java generics
(1 answer)
Closed 6 years ago.
<T extends Number> void m1(List<T> list) {
list.add(list.get(0));
}
void m2(List<? extends Number> list) {
list.add(list.get(0));
}
I found difficult to understand the difference between above two methods.
First method m1() compiles successfully, but method m2() produces a compiler error:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ? extends Number> is not applicable for the arguments (capture#2-of ? extends Number)
Because you cant add an iten on a list of type with upper bounds! You could have a List or List, where one doesnt fit in the other for modifications operations!
List<? extends Number> list = new ArrayList<Integer>();
List<? extends Number> list = new ArrayList<Double>();
List<? extends Number> list = new ArrayList<Long>();
In this case, the variable list could have any type in instance that extends Number. So you can pass it in your method, for example. But there, you don't really know which the type could be. You could have a ArrayList<Integer> and saying to it add a new Double. In compile time makes sense, because Double extends Number, but in runtime the list could no be of this type and throw an Exception.
Just remember that, when you use the upper bounds, <? extends T>, you can't modify the list, just read it! There is the Oracle tutorial (see Wildcards chapter contents - Upper Bounded Wildcards, Lower Bounded Wildcards etc.)
I can't find any example where wildcards can't be replaced by a generic.
For example:
public void dummy(List<? extends MyObject> list);
is equivalent to
public <T> void dummy(List<T extends MyObject> list);
or
public <T> List<? extends T> dummy2(List<? extends T> list);
is equivalent to
public <T, U> List<U extends T> dummy(List<U extends T> list);
So I don't undertand why wildcard was created as generics is already doing the job. Any ideas or comments?
Nope, it is not always replaceable.
List<? extends Reader> foo();
is not equivalent to
<T> List<T extends Reader> foo();
because you don't know the T when calling foo() (and you cannot know what List<T> will foo() return. The same thing happens in your second example, too.
The demonstration of using wildcards can be found in this (my) answer.
An easy answer is that, deeper level wildcards can't be replaced by a type variable
void foo( List<List<?>> arg )
is very different from
<T>
void foo( List<List<T>> arg)
This is because wildcard capture conversion is only applied to 1st level wildcards. Let's talk about these.
Due to extensive capture conversion, in most places, compiler treats wildcards as if they are type variables. Therefore indeed programmer can replace wildcard with type variables in such places, a sort of manual capture conversion.
Since a type variable created by compiler for capture conversion is not accessible to programmer, this has the restricting effect mentioned by #josefx. For example, compiler treats a List<?> object as a List<W> object; since W is internal to compiler, although it has a method add(W item), there's no way for programmer to invoke it, because he has no item of type W. However, if programmer "manually" converts the wildcard to a type variable T, he can have an item with type T and invoke add(T item) on it.
Another rather random case where wildcard can't be replaced type variable:
class Base
List<? extends Number> foo()
class Derived extends Base
List<Integer> foo()
Here, foo() is overriden with a covariant return type, since List<Integer> is a subtype of List<? extends Number. This won't work if the wildcard is replaced with type variable.
There is a usage difference for your examples.
public <T> List<? extends T> dummy2(List<? extends T> list);
returns a list that can contain an unknown subtype of T so you can get objects of type T out of it but can't add to it.
Example T = Number
List<? extends Number> l = new ArrayList<Integer>(Arrays.asList(new Integer(1)));
//Valid since the values are guaranteed to be a subtype of Number
Number o = l.get(0);
//Invalid since we don't know that the valuetype of the list is Integer
l.add(new Integer(1));
So the wildcard can be used to make some operations invalid, this can be used by an API to restrict an interface.
Example:
//Use to remove unliked numbers, thanks to the wildcard
//it is impossible to add a Number
#Override public void removeNumberCallback(List<? extends Number> list){
list.remove(13);
}
Is there a difference between
<N extends Number> Collection<N> getThatCollection(Class<N> type)
and
Collection<? extends Number> getThatCollection(Class<? extends Number>)
They expose different interfaces and contract for the method.
The first declaration should return a collection whose elements type is the same of the argument class. The compiler infers the type of N (if not specified). So the following two statements are valid when using the first declaration:
Collection<Integer> c1 = getThatCollection(Integer.class);
Collection<Double> c2 = getThatCollection(Double.class);
The second declaration doesn't declare the relationship between the returned Collection type argument to the argument class. The compiler assumes that they are unrelated, so the client would have to use the returned type as Collection<? extends Number>, regardless of what the argument is:
// Invalid statements
Collection<Integer> c1 = getThatCollection(Integer.class); // invalid
Collection<Double> c2 = getThatCollection(Double.class); // invalid
Collection<Number> cN = getThatCollection(Number.class); // invalid
// Valid statements
Collection<? extends Number> c3 = getThatCollection(Integer.class); // valid
Collection<? extends Number> c4 = getThatCollection(Double.class); // valid
Collection<? extends Number> cNC = getThatCollection(Number.class); // valid
Recommendation
If indeed there is a relationship between the type between the returned type argument and the passed argument, it is much better to use the first declaration. The client code is cleaner as stated above.
If the relationship doesn't exist, then it is still better to avoid the second declaration. Having a returned type with a bounded wildcard forces the client to use wildcards everywhere, so the client code becomes clattered and unreadable. Joshua Bloch emphisize that you should Avoid Bounded Wildcards in Return Types (slide 23). While bounded wildcards in return types may be useful is some cases, the ugliness of the result code should, IMHO, override the benefit.
In this particular case, no. however the second option is more flexible since it would allow you to return a collection that contains elements of a different type (even though it would also be a Number) than the type contained by the collection parameter.
Concrete example:
Collection<? extends Number> getRoot(Class<? extends Number> number){
ArrayList<Integer> result=new ArrayList<Integer>();
result.add(java.util.Math.round(number);
return result)
}