Below is a quote on comparison betweenunbounded wildcard types
vs raw types
, from Java generics and collection
by Maurice Naftalin and Philip Wadler.
We recommend using unbounded wildcard types in preference to raw types because they provide stronger static typing guarantees; many mistakes that are caught as an error when you use unbounded wildcards will only be flagged as a warning if you use raw types.
But the book doesn't provide an code example to explain the situation. I was wondering if someone could add to the explanation by providing an code example?
Well, you could adapt some of the examples of that same chapter to reproduce a case of this.
For example, consider the following generic class:
class Node<E> {
private E value;
@Override public String toString(){ return value.toString(); }
}
Now, imagine that you write the following piece of code, which is wrong:
Object o = new Node<Integer>(10);
Node<String> node = new Node<>("Hello");
if(o instanceof Node) {
Node other = (Node) o;
other.value = node.value; //Uh oh! Warning
}
System.out.println(node); //Hello
System.out.println(other); //Hello - WTH!
If you try to compile this, you would only get a warning, but it would still compile just fine:
javac -Xlint:unchecked Node.java
Node.java:21: warning: [unchecked] unchecked assignment to variable value as member of raw type Node
other.value = node.value;
^
1 warning
However, if you change the code to use unbounded wildcards:
Object o = new Node<Integer>(10);
Node<String> node = new Node<>("Hello");
if(o instanceof Node<?>) {
Node<?> other = (Node<?>) o;
other.value = node.value; //Uh oh! Compiler error
}
Now you would get the following error when compiling:
javac -Xlint:unchecked Node.java
Node.java:21: error: incompatible types: String cannot be converted to CAP#1
other.value = node.value;
^
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
1 error
So, as you can see the unbounded wildcard offers better type checking guarantees than the raw type.