I was reading about generics and I did not understand the need for unbound wildcards and how it differs from raw type. I read this question but still did not get it clearly.
How
List<?>
differs fromList<Object>
The main difference is that the first line compiles but the second does not:
List<?> list = new ArrayList<String> ();
List<Object> list = new ArrayList<String> ();
However, because you don't know what the generic type of List<?>
is, you can't use its parameterized methods:
List<?> list = new ArrayList<String> ();
list.add("aString"); //does not compile - we don't know it is a List<String>
list.clear(); //this is fine, does not depend on the generic parameter type
As for the difference with raw types (no generics), the code below compiles and runs fine:
List list = new ArrayList<String> ();
list.add("aString");
list.add(10);
List is useful in a method signature to call methods that never require the type parameter, i.e., read from the list or rotate it, for instance.
void someMethod(List<?> list) {
list.clear(); // I will never add anything to the list in here
}
You will never add anything or otherwise modify the list with respect to the type it holds as you cannot add anything to the list except null in methods with this signature and thus you won't ever break type safety. Raw List on the other hand you can do anything to, which as we all know can result in a type safety violation.
void someMethod2(List list) {
list.add(new WeaselFurBrush());
}
List list1 = new ArrayList<String>();
someMethod2(list1);// oops
Can someone please explain the difference between unbound wildcard and raw type in layman language.
Unbound wildcard type can maintain collection’s type invariant, and raw type cannot. As Joshua Bloch says in his Effective Java,
You can put any element into a collection with a raw type, easily corrupting the collection’s type invariant(as demonstrated by the unsafeAdd method on page 112); you can’t put any element (other than null) into a Collection<?>.
So, as long as you assign a list of parameterized type to a list of unbound wildcard type, collection’s type invariant will be maintained.
List<String> list1 = new ArrayList();
list1.add("foo");
list1.add("bar");
List<?> list2 = list1;
If you assign a list of raw type whose elements are of different types, unbound wildcard type will not maintain collection’s type invariant, as the list is originally of type variant.
List list1 = new ArrayList();
list1.add(1);
list1.add("foo");
List<?> list2 = list1;
How List<?>
differs from List<Object>
?
List<Object> l1 = new ArrayList();
List<?> l2 = new ArrayList();
l1.add("Object");
//l2.add("Object"); incorrect
l2.add(null);
You can only add null-value to the List<?>
Personally, I found this additional link from the Java tutorial on wildcards helpful.
One of the main differences I see between List<?>
and List
is that the former can only ever be useful for reading from it's elements (unless you really want to add null
), the latter allows (unchecked) adding of arbitrarily typed objects to it with possibly unexpected side-effects.