Given this example from the generics tutorial.
List<String> list = new ArrayList<>();
list.add("A");
// The following statement should fail since addAll expects
// Collection<? extends String>
list.addAll(new ArrayList<>());
Why does the last line not compile, when it seems it should compile. The first line uses a very similar construct and compiles without a problem.
Please explain elaborately.
Diamond Operator: Diamond operator was introduced in Java 7 as a new feature. The main purpose of the diamond operator is to simplify the use of generics when creating an object. It avoids unchecked warnings in a program and makes the program more readable.
It's called diamond operator and infers the generic type from the left hand side, if possible.
First of all: unless you're using Java 7 all of this will not work, because the diamond <>
has only been introduced in that Java version.
Also, this answer assumes that the reader understands the basics of generics. If you don't, then read the other parts of the tutorial and come back when you understand those.
The diamond is actually a shortcut for not having to repeat the generic type information when the compiler could find out the type on its own.
The most common use case is when a variable is defined in the same line it's initialized:
List<String> list = new ArrayList<>(); // is a shortcut for
List<String> list = new ArrayList<String>();
In this example the difference isn't major, but once you get to Map<String, ThreadLocal<Collection<Map<String,String>>>>
it'll be a major enhancement (note: I don't encourage actually using such constructs!).
The problem is that the rules only go that far. In the example above it's pretty obvious what type should be used and both the compiler and the developer agree.
On this line:
list.addAll(new ArrayList<>());
it seems to be obvious. At least the developer knows that the type should be String
.
However, looking at the definition of Collection.addAll()
we see the parameter type to be Collection<? extends E>
.
It means that addAll
accepts any collection that contains objects of any unknown type that extends the type of our list
. That's good because it means you can addAll
a List<Integer>
to a List<Number>
, but it makes our type inference trickier.
In fact it makes the type-inference not work within the rules currently laid out by the JLS. In some situations it could be argued that the rules could be extended to work, but the current rules imply don't do it.
The explanation from the Type Inference documentation seems to answer this question directly ( unless I'm missing something else ).
Java SE 7 and later support limited type inference for generic instance creation; you can only use type inference if the parameterized type of the constructor is obvious from the context. For example, the following example does not compile:
List<String> list = new ArrayList<>();
list.add("A");
// The following statement should fail since addAll expects
// Collection<? extends String>
list.addAll(new ArrayList<>());
Note that the diamond often works in method calls; however, for greater clarity, it is suggested that you use the diamond primarily to initialize a variable where it is declared.
In comparison, the following example compiles:
// The following statements compile:
List<? extends String> list2 = new ArrayList<>();
list.addAll(list2);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With