Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between unbounded wildcard type List<?> and raw type List?

Tags:

Could you help me understand the difference between unbounded wildcard type List and raw type List?

List<?> b;    // unbounded wildcard type List a;       // raw type 


Along with this can anybody help me understand what is a bounded type parameter list?

List<E extends Number> c; 
like image 495
Ashish Agarwal Avatar asked Aug 29 '09 12:08

Ashish Agarwal


People also ask

What is unbounded wildcard?

The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach: If you are writing a method that can be implemented using functionality provided in the Object class.

What is the difference between List Object and raw type List?

List<Object> is not compatible with a List of any other parameter. However, a raw List is compatible with List s of all parameters.

What Does List <?> Mean in Java?

Java List is an ordered collection. Java List is an interface that extends Collection interface. Java List provides control over the position where you can insert an element. You can access elements by their index and also search elements in the list.

What is the difference between ArrayList and ArrayList <?> In Java?

The List is an interface, and the ArrayList is a class of Java Collection framework. The List creates a static array, and the ArrayList creates a dynamic array for storing the objects. So the List can not be expanded once it is created but using the ArrayList, we can expand the array when needed.


2 Answers

Here's a summary of the three:

  • List: A list with no type parameter. It is a list whose elements are of any type -- the elements may be of different types.

  • List<?>: A list with an unbounded type parameter. Its elements are of a specific, but unknown, type; the elements must all be the same type.

  • List<T extends E>: A list with a type parameter called T. The supplied type for T must be of a type that extends E, or it is not a valid type for the parameter.

like image 179
John Feminella Avatar answered Oct 11 '22 15:10

John Feminella


You should really look at Effective Java, Item 23: Don't use raw types in new code.

To use the example from that book, consider the following example... what if you have a collection where you do not care what types of elements are in it. For example, you want to see how many elements are in common between two sets. You might come up with the following:

public static int numElementsInCommon(Set s1, Set s2) {   int result = 0;   for (Object o : s1) {     if (s2.contains(o)) {       ++result;     }   }   return result; } 

This example, while it works, is not a good idea to use because of the use of raw types. Raw types just aren't type safe at all... you could end up modifying the set in a way that is not type safe and corrupt your program. Instead, err on the side of caution and use the type safe alternative:

public static int numElementsInCommon(Set<?> s1, Set<?> s2) {   int result = 0;   for (Object o : s1) {     if (s2.contains(o)) {       ++result;     }   }   return result; } 

The difference is that you can only add null to a Set<?>, and you CANNOT assume anything about the element you take out of a Set<?>. If you use a raw Set, you can add anything you want to it. The numElementsInCommon method is a good example where you don't even need to add anything and you don't need to assume anything about what is in the set. That's why it's a good candidate for using the ? wildcard.

Hope this helps. Read that whole Item in Effective Java and it will really become clear.

To answer the second part of your question... remember that I said when you use the ? wildcard, you cannot assume anything about the element you take out of the set? What if you do need to make an assumption about the interface of the object you removed from the set. For example, suppose you want to keep track of a set of Cool things.

public interface Cool {   // Reports why the object is cool   void cool(); } 

Then you might have some code like this:

public static void reportCoolness(Set s) {   for (Object item : s) {     Cool coolItem = (Cool) item;     coolItem.cool();   } } 

This is not type safe... you need to make sure you passed in a set with only Cool objects. To fix it, you might say:

public static void reportCoolness(Set<Cool> s) {   for (Cool coolItem : s) {     coolItem.cool();   } } 

This is great! Does exactly what you want and is type safe. But what if later you have this:

public interface ReallyCool extends Cool {   // Reports why the object is beyond cool   void reallyCool(); } 

Since all ReallyCool objects are Cool, you ought to be able to do the following:

Set<ReallyCool> s = new HashSet<ReallyCool>(); // populate s reportCoolness(s); 

But you can't do that because generics have the following property: Suppose B is a subclass of A, then Set<B> is NOT a subclass of Set<A>. The technical talk for this is "Generic types are invariant." (As opposed to covariant).

To get the last example to work you would need to create a Set<Cool> by casting (safely) every element in the Set<ReallyCool>. To avoid letting clients of your api go through this nasty, unnecessary code, you can just make the reportCoolness method more flexible like this:

public static void reportCoolness(Set<? extends Cool> s) {   for (Cool coolItem : s) {     coolItem.cool();   } } 

Now your method takes any Set that contains elements that are Cool or any subclass of Cool. All of these types adhere to the Cool api... so we can safely call the cool() method on any element

Make sense? Hope this helps.

like image 26
Tom Avatar answered Oct 11 '22 15:10

Tom