List and List<?> in Java - java

What is the difference between List and List<?>? I know I can't add any element to the List<?>. I have a code:
List<String> myList = new ArrayList<String>();
processList(myList);
processListGeneric(myList);
public static void processList(List myList) {
Iterator it = myList.iterator();
while(it.hasNext())
System.out.println(it.next());
}
public static void processListGeneric(List<?> myList) {
Iterator<?> it = myList.iterator();
while(it.hasNext())
System.out.println(it.next());
}
The name of the two methods cannot be the same, because it causes compile time error. So is there any difference in these two approaches?

Both do the same, but in second case compiler is informed that you really want a list with no type bounds and raises no warnings. If you are working with Java 5 or later you are encouraged to use second approach.

The difference is that you can't add anything to a List<?>, since it's a List of an unknown type.
For example, you are prevented from doing this:
List<Integer> listOfInt = new ArrayList<Integer>();
List<?> list = listOfInt;
list.add("hello?"); // Compile-time error
You can add anything you want to the base type List since the type of the list items is not checked.

List<?> (pronounced "collection of unknown")is a collection whose element type matches anything. It's called a wildcard type for obvious reasons.
Refer to the following code
List<String> myList = new ArrayList<String>();
myList.add("John");
String name = myList.get(0);
System.out.println(name); //print John
List<?> myListNew = myList;
myListNew.add("Sam");//Compile time error
String nameNew = myListNew.get(0);//Compile time error
Object newName = myListNew.get(0);
System.out.println(newName);//Prints John
Since we don't know what the element type of myListNew stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
On the other hand, given a List<?>, we can call get() and make use of the result. The result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected.

List is raw type and List< ?> is wildcard type. Take look http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

Both of them behave same. Using parametrized notation you are just avoiding any warnings in Java5 and above. You cannot have both the syntax in same java file because due to type erasure compiled unit has two methods with exactly same signature in same class file and thus violating language rules.
Following is what you would be getting from compiler:
Method processList(List) has the same erasure processList(List) as another method in type ...

Just writing List without a type parameter is deprecated, but otherwise the same as writing List<Object>. So the question becomes "What's the difference between List<Object> and List<?> and which one should I use?".
As you already know, you can't add (anything other than null) to a List<?>, so if you need to add to a list, you should use a List<Object> (or a more specific type where applicable, of course). On the other hand, a method that takes a List<Object>, only accepts List<Object>s and not any lists that contain a subclass of Object. That is, it would not accept a List<String>. If the method takes a List<?> however, it accepts any kind of list. So if you don't need to add to the list, you should use List<?> as it is more general.

The second method uses generics (introduced in Java 5).
One important distinction is the <?> represents a single type, not any object like this:
List<? extends Object> myList
So you could say that using the first method (without the wildcard syntax) is more flexible, as you'd be able to add any object to your List. Although, you'll get a (compiler) warning that you declaration should be parameterized.
Using the <?> unbounded wildcard syntax will avoid the warning, but you're telling the compiler it could be a list of any type, instead of actually using generics to enforce type safety. You are strongly encouraged to use generics to assist you in making your application type safe.
If, for example, you know that the list should only ever contain String objects, declare it thus:
List<String> myList
Then you'll avoid unnecessary casting of use of the instanceof operator, etc.
Here's a brief tutorial on generics in Java, for your information:
http://javarevisited.blogspot.co.uk/2011/09/generics-java-example-tutorial.html

Related

Difference between ArrayAdapter<String> adapter and ArrayAdapter adapter? [duplicate]

Can someone explained, as detailed as possible, the differences between the following types?
List
List<Object>
List<?>
Let me make this more specific. When would I want to use
// 1
public void CanYouGiveMeAnAnswer(List l) { }
// 2
public void CanYouGiveMeAnAnswer(List<Object> l) { }
// 3
public void CanYouGiveMeAnAnswer(List<?> l) { }
As the other posts have noted, you are asking about a Java feature called generics. In C++, this is called templates. This feature in Java is usually easier to work with than the that found in C++.
Let me answer your questions functionally (if that's not a naughty word for OO discussions).
Before generics, there were concrete classes like Vector.
Vector V = new Vector();
Vectors hold any object you give them.
V.add("This is an element");
V.add(new Integer(2));
v.add(new Hashtable());
They do this by casting all values given to it into an Object (the root of all Java classes). When you attempt to retrieve the values stored in your Vector, you need to cast the value back into the original class (if you want to do anything meaningful with it).
String s = (String) v.get(0);
Integer i = (Integer) v.get(1);
Hashtable h = (Hashtable) v.get(2);
Casting gets old fast. More than that, the compiler complains to you about unchecked casts. The most urgent problem with casting like this is that consumers of your Vector have to know the classes of its values at compile time in order to cast correctly. In cases where the producer of the Vector and the consumer of the same are completely isolated from each other (think RPC messages), this can be a fatal issue.
Enter generics. Generics attempt to create strongly typed classes to do generic operations.
ArrayList<String> aList = new ArrayList<String>();
aList.add("One");
String element = aList.get(0); // no cast needed
System.out.println("Got one: " + element);
The Design Patterns book encourages the reader to think in terms of contracts, not concrete types. There is wisdom (and code re-use) in divorcing variables from their implementing class.
With this in mind, you might think that all implementations List objects should do the same set of things: add(), get(), size(), etc. With a little reflection, you can imagine many implementations of List operations that obey the List contract in various ways (e.g. ArrayList). However, the type of data these objects deal with is orthogonal to the actions performed on them.
Put it all together and you'll see the following kinds of code frequently:
List<String> L = new ArrayList<String>();
You should read that as "L is a kind of List that deals with String objects". When you start dealing with Factory classes, it is critical to deal with contracts rather than specific implementations. Factories produce objects of various types at runtime.
Using generics is pretty easy (most of the time).
One day you may decide you want to implement your own generic class. Perhaps you want to write a new database abstraction interface that elides the differencesbetween various data stores. When you define that generic class, you will use <t> as a placeholder for the kind of object that will be manipulated by the methods.
If you are still confused, use the generic classes for List until you are comfortable. Later, you can dive into the implementation with a bit more confidence. Or you can look at the source code for the various List classes that ship with the JRE. Open source is great that way.
Have a look at the Oracle/Sun docs about generics.
Cheers.
In my own simple terms:
List
Would declare an ordinary collection, can hold any type, and will always return Object.
List<Object>
Will create a list that can hold any type of object, but can only get assigned a another List<Object>
For instance this doesn't work;
List<Object> l = new ArrayList<String>();
Of course you can add anything but only can pull Object.
List<Object> l = new ArrayList<Object>();
l.add( new Employee() );
l.add( new String() );
Object o = l.get( 0 );
Object o2 = l.get( 1 );
Finally
List<?>
Will let you assign any type, including
List <?> l = new ArrayList();
List <?> l2 = new ArrayList<String>();
This would be called collection of unknown and since the common denominator of unknown is Object you will be able to fetch Objects ( a coincidence )
The importance of unknown comes when its used with subclassing:
List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles
List<? extends Collection> l = new ArrayList<String>(); // doesn't,
// because String is not part of *Collection* inheritance tree.
I hope using Collection as the type doesn't create confusion, that was the only tree that came to my mind.
The difference here, is that l is a collection of unknow that belongs to the Collection hierarchy.
To add to the already good answers here:
Method arguments:
List<? extends Foo>
good choice if you don't intend to alter the list, and only care that everything in the list is assignable to type 'Foo'. This way, the caller can pass in a List<FooSubclass> and your method works. Usually the best choice.
List<Foo>
good choice if you intend to add Foo objects to the list in your method. The caller may not pass in a List<FooSubclass>, as you intend to add a Foo to the List.
List<? super Foo>
good choice if you intend to add Foo objects to the list, and it's not important what else is in the list (ie, you are ok getting a List<Object> that contains a 'Dog' that has nothing to do with Foo).
Method return values
just like method arguments, but with the benefits reversed.
List<? extends Foo>
Guarantees that everything in the returned List has type 'Foo'. It might be List<FooSubclass> though. Caller cannot add to the List. This is your go-to choice and the most common case by far.
List<Foo>
Just like List<? extends Foo> but also allows the caller to add to the List. Less common.
List<? super Foo>
allows the caller to add Foo objects to the List, but does not guarantee what will be returned from list.get(0)... it could be anything from Foo to Object. The only guarantee is that this won't be a list of 'Dog' or some other choice that would prevent list.add(foo) from being legal. Very rare use case.
I hope that helps. Good luck!
ps. To sum up... two questions...
do you need to add to the List? Do you care what is in the list?
yes yes - use List<Foo>.
yes no - use List<? super Foo>.
no yes - use <? extends Foo> --- most common.
no no - use <?>.
I refer you to the excellent Java Generics tutorial, and the "advanced" Generics tutorial, both available from Sun Microsystems. Another great resource is the Java Generics and Collections book.
I will try to answer this in detail. Before generics we were having only List (a raw list) and it can hold almost anything we can think of.
List rawList = new ArrayList();
rawList.add("String Item");
rawList.add(new Car("VW"));
rawList.add(new Runnable() {
#Override
public void run() {
// do some work.
}
});
The major problem with the raw list is when we want to get any element out of such list it can only guarantee that it would be Object and for that reason we need to use casting as:
Object item = rawList.get(0); // we get object without casting.
String sameItem = (String) rawList.get(0); // we can use casting which may fail at runtime.
So conclusion is a List can store Object (almost everything is Object in Java) and always returns an Object.
Generics
Now lets talk about generics. Consider the following example:
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
stringsList.add(new Car("Fiat")); //error
String stringItem = stringsList.get(0);
In the above case we cannot insert anything other than String in stringsList as Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. And we get error when we try to insert a Car instance in it. Also it eliminates cast as you can check when we invoke get method. Check this link for understanding why we should use generics.
List<Object>
If you read about type erasure then you will understand that List<String>, List<Long>, List<Animal> etc. will be having different static types at compile time but will have same dynamic type List at run time.
If we have List<Object> then it can store only Object in it and almost everything is Object in Java. So we can have:
List<Object> objectList = new ArrayList<Object>();
objectList.add("String Item");
objectList.add(new Car("VW"));
objectList.add(new Runnable() {
#Override
public void run() {
}
});
Object item = objectList.get(0); // we get object without casting as list contains Object
String sameItem = (String) objectList.get(0); // we can use casting which may fail at runtime.
It seems List<Object> and List are same but actually they are not. Consider the following case:
List<String> tempStringList = new ArrayList<>();
rawList = tempStringList; // Ok as we can assign any list to raw list.
objectList = tempStringList; // error as List<String> is not subtype of List<Obejct> becuase generics are not convariant.
You can see we can assign any list to raw list and major reason for that is to allow backward compatibility. Also List<String> will be converted to List at run time due to type erasure and assignment will be fine anyways.
But List<Object> means it can only refer to a list of objects and can also store objects only. Even though String is subtype of Object we cannot assign List<String> to List<Object> as generics are not covariant like arrays. They are invariant. Also check this link for more. Also check the difference between List and List<Object> in this question.
List<?>
Now we are left with List<?> which basically means list of unknown type and can refer to any list.
List<?> crazyList = new ArrayList<String>();
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
crazyList = stringsList; // fine
The character ? is known as wildcard and List<?> is a list of unbounded wildcard. There are certain points to observe now.
We cannot instantiate this list as the following code will not compile:
List<?> crazyList = new ArrayList<?>(); // any list.
We can say a wildcard parameterized type is more like an interface type as we can use it to refer to an object of compatible type but not for itself.
List<?> crazyList2 = new ArrayList<String>();
We cannot insert any item to it as we don't know what actually the type would be.
crazyList2.add("Apple"); // error as you dont actually know what is that type.
Now question arises When would I want to use List<?>?
You can think of this as a read-only list where you don't care about the type of the items. You can use it to invoke methods like returning the length of the list, printing it etc.
public static void print(List<?> list){
System.out.println(list);
}
You can also check the difference between List, List<?>, List<T>, List<E>, and List<Object> here.
Simplest explanation which is not "RTFM":
List
Will generate lots of compiler warnings, but is mostly equivalent to:
List<Object>
While:
List<?>
basically means its something generic, but you don't know what the generic type is. Its great for getting rid of compiler warnings when you cant modify the return types of other things that just returned List. Its much more useful in the form:
List<? extends SomeOtherThing>
The shortest possible explanation is: The second item is a list that can hold any type, and you can add objects to it:
List<Object>
The first item you list is treated as essentially equivalent to this, except you will get compiler warnings because it is a "raw type".
List
The third is a list that can hold any type, but you cannot add anything to it:
List<?>
Basically, you use the second form (List<Object>) when you truly have a list that can contain any object and you want to be able to add elements to the list. You use the third form (List<?>)when you receive the list as a method return value and you will iterate over the list but never add anything to it Never use the first form (List) in new code compiling under Java 5 or later.
I'd put it this way: While List and List<Object> can contain any type of objects, List<?> contains elements of an unknown type, but once that type is captured, it can only contain elements of that type. Which is why it is the only type safe variant of those three, and therefore generally preferable.
To complement the tutorials mentioned by Rob, here's a wikibook explaining the topic:
http://en.wikibooks.org/wiki/Java_Programming/Generics
Edit:
No restrictions on type of items in list
Items in list must extend Object
Wildcard used by itself, so it matches anything
Would it be naive of me to conclude at this point that there's hardly any/no difference at all?
When would I want to use
public void CanYouGiveMeAnAnswer( List l ){}
When you cant to do all the casting your self.
When would I want to use
public void CanYouGiveMeAnAnswer( List l<Object> ){}
When you want to restrict the type of the List. For instance, this would be an invalid argument.
new ArrayList<String>();
When would I want to use
public void CanYouGiveMeAnAnswer( List l<?> ){}
Mostly never.
List, List<?>, and List<? extends Object> are the same thing. The second is more explicit. For a list of this type, you cannot know what types are legal to put into it, and you don't know anything about the types you can get out of it, except that they will be objects.
List<Object> specifically means that the list contains any sort of object.
Let's say we make a list of Foo:
List<Foo> foos= new ArrayList<Foo>();
It is not legal to put a Bar into foos.
foos.add(new Bar()); // NOT OK!
It is always legal to put anything into a List<Object>.
List<Object> objs = new ArrayList<Object>();
objs.add(new Foo());
objs.add(new Bar());
But you mustn't be allowed to put a Bar into a List<Foo> - that's the whole point. So that means that this:
List<Object> objs = foos; // NOT OK!
is not legal.
But it's ok to say that foos is a list of something but we don't know specifically what it is:
List<?> dontKnows = foos;
But that then means that it must be prohibited to go
dontKnows.add(new Foo()); // NOT OK
dontKnows.add(new Bar()); // NOT OK
because the variable dontKnows does't know what types are legal.
List < Object > is meant to pass input type parameter of an Object. While List < ? > represents Wildcard type. The wildcard < ? > is of Unknown parameter type. The wildcard cannot be used as a type argument for a generic method and cannot be used to create a generic instance of a class. Wildcard can be used to extend a subtype class, List < ? extends Number >. To relax the restriction of an Object type and in this case to relax "Number" Object type.
In terms of List functionality differences, the other responses already answered this question. In terms of applicable rules of Java generics, it's a complicated topic. I wrote an in-depth article about Java generics rules, this is the link: https://medium.com/#royalilin/java-generics-rules-1d05de86e9cb

how the type information is retrieved in generics (Erasure) in Java?

by using generics, we detect any possible during compilation.
for example,
List<String> list = new ArrayList<String>();
//list.add(new Integer(45)); This will cause compilation error.
list.add("car");
list.add("bus");
list.add("bike");
String vehicle = list.get(0); //compiler-generated cast
when we use raw type instead of generics before Java 1.5, it needs explicit casting.
for example,
List list2 = new ArrayList();
list.add("car");
list.add("bus");
list.add("bike");
String vehicle = (String)list.get(0); //explicit casting is necessary
however with generics, type erasure occurs. that is the type information is lost in runtime.
if, that is so, how does the JVM know what object type it is retrieving during runtime, whether it is a string object or a person object (compiler generated cast above). but this valid with generics, which is can cause runtime errors.
List<Object> test = new ArrayList<Object>();
test.add("hello");
test.add(new Integer(34));
finally, Joshua Bloch mentions on page 115 (item 23, effective java) that
Set<Object> is parameterized type representing a set that can contain objects of any type,
Set<?> is a wild card type representing a set that can contain only objects of some unknown type
and Set is a raw type, which opts out of the generic type system.
I do understand what he means by the above statement. some clarifications will help
The compiler inserts cast operations when retrieving items from generic methods; this is the only way that the JVM knows to treat the result of list.get(0) as a String. This is why heap pollution (inserting the wrong type of object into a generic collection) can result in a ClassCastException at runtime.
Regarding the wildcards:
Set<Object>'s generic type is exactly Object. You can insert and retrieve Object instances from it, but you can't pass a Set<Integer> to a method expecting a Set<Object>, since the method might be planning to add a non-Integer object to the set.
Set<?> has an unspecified generic type. A method can retrieve anything from it as an Object (since everything is an Object) and can call universal methods on it like hashCode or toString, but it can't add anything to the set.
Set, as you mention, is the raw type and shouldn't be used in new code.
I am not very sure, but what I understand by type information is lost at runtime is that there is no way at runtime that a collection is of some specific type. If you add a String to a collection, it will be a String only but the collection does not enforce that all elements should be of type String
Generics are implemented by Java compiler as a front-end conversion
called erasure. Type erasure applies to the use of generics. When
generics are used, they're converted into compile time checks and run
time type casts.
Due to type erasure mechanism this code:
List<String> a = new ArrayList<String>();
a.add("foo");
String x = a.get(0);
gets compiled into this:
List a = new ArrayList();
a.add("foo");
String x = (String) a.get(0);
Notice extra cast inserted into compiled compiled-code after type erasure.
PS: #chrylis has already provided good explanation about your 2nd part of question.
Well, this stackoverflow question here can help you .
Eclipse might be using this method to find out the fields in a class and their generic type if any. Please have a look.

Warning ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized
In order to save an ArrayList with payments done by one member I want to change the List of Payment ID's into a string, so I created the following method:
public String fromArraytoString(ArrayList items){
JSONObject json = new JSONObject();
json.put("uniqueArrays", new JSONArray(items));
return json.toString();
}
But I get the following warning:
ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized
Can anyone explain me why?
You definitely should read this tutorial on Java generics:
http://docs.oracle.com/javase/tutorial/java/generics/
In a nutshell:
Many Java classes and types (called generic classes or generic types), typically collections, have so called type parameters, such as E in ArrayList<E> (E is just an arbitrary chosen name, other classes name it as T or whatever):
public class ArrayList<E> extends ... {
public E get(int index) { ... }
public boolean add(E element) { ... }
// other methods...
}
Now, when you create an instance of such class, you define a concrete value of the type parameter, for example String (E can usually be evaluated to whatever type you want):
ArrayList<String> stringList = new ArrayList<String>();
From now on, all the Es are "replaced" by String for the stringList variable, so you can add only Strings to it and get only Strings from it. The compiler checks for you that you don't mistakenly add an object of another type:
stringList.add(Integer.valueOf(1));
// compile error - cannot add Integer to ArrayList of Strings
However, because generics were added to Java 5, it is still possible to write code without them for backwards compatibility. So you can write:
ArrayList list = new ArrayList();
But you lose all the type checking benefits. Es in method signatures become simply Objects.
list.add(Integer.valueOf(42)); // adding an Integer
list.add("aaa"); // adding a String
Object something = list.get(0); // unknown type of returned object, need to cast
Integer i0 = (Integer) something; // this unsafe cast works...
Integer i1 = (Integer) list.get(1); // but this fails with a ClassCastException
// because you cannot cast a String to Integer
The fact that using a raw type (that is a generic type with its type parameters omitted) is unsafe, is the reason for the warning you've got. Instead of just ArrayList, use ArrayList<String> or ArrayList<Integer> or whatever the type of your items is.
What kind of objects are stored in the ArrayList? You need to add it to the declaration. It's always
ArrayList<Type>
So if it's a list of JSONObjects, you would put
ArrayList<JSONObject>
Hope that helps.
JsonArray's constructor expects to receive a generic type Collection with parameter T, while items's type is ArrayList without type specified(i.e raw type). You may check this question to get some idea about raw type: What is a raw type and why shouldn't we use it?
Solution 1(recommended): pass items with paramter T or specify concrete type such as String. This question might help you in your specific problem: convert ArrayList<MyCustomClass> to JSONArray.
Solution 2: add #SuppressWarnings("unchecked") before the method fromArraytoString.
This is not recommended, but you can refer to this question: What is SuppressWarnings ("unchecked") in Java?
This is because Java compiler tries to do certain checking for you. The way you have written it you effectively tell compiler you will receive ArrayList of Object's as parameter.
It's simply encouraging you to specify class of objects you will to store in ArrayList. Specifying ArrayList<MyClass> or ArrayList <?> would get rid of the warning. Second version effectively tells compiler that you would pass ArrayList of objects of class not known at compile time.
I think it might be useful for you to read a bit about generics in Java.
http://docs.oracle.com/javase/tutorial/java/generics/

Java: Wildcards again

In my last question (thank you all that answer me), I have learnt the difference between List<Object> and List<?>.
However I still can't see the usefulness of wildcards.
I have two ArrayLists:
ArrayList<Integer> li = new ArrayList<Integer>(Arrays.asList(1,2,3));
ArrayList<String> ls = new ArrayList<String>(Arrays.asList("one","two","three"));
Now, look at the two blocks of code below:
static void printList(ArrayList<?> list)
{
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
and
static <T> void printList(ArrayList<T> list)
{
for (T elem: list)
System.out.print(elem + " ");
System.out.println();
}
When I call:
printList(li);
printList(ls);
Both methods return the output:
1 2 3
one two three
However the second solution, in the for loop, instead of Objects I use parametrized types (much more elegant I think).
So, the main question remains: Why do we need wildcards?
If the question is "usefulness of wildcards":
Wildcards are useful when only partial knowledge about the type parameter is required.
"Partial knowledge" is implemented by the upper and lower bounds (? super T or ? extends T); if you use only the unbound wildcard ( ? ) you mean no knowledge at all, and you can't see where wildcards are really useful.
Wildcards can be used in composition with type parameters, to create relationships between the type of method parameters, return type and exception types.
So an example of useful wildcard is
class ListManager<T> {
public void add(T item, List<? super T> list) {
[... some useful operation ...]
list.add(item);
}
}
public class Main {
public static void main(String[] args) {
List<Object> list = new ArrayList<Object>();
Integer item = 10;
ListManager<Integer> manager = new ListManager<Integer>();
manager.add(item, list);
}
}
The method "ListManager.add()" creates a relationship between type of "list" and type of "item".
The operation on "list" is always type safe, but you can use method "add" with list of different parameter type: we have used the minimum constraint on parameter "list".
(see also jls7 documentation)
In the Java Generics Tutorial it says:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
On the other hand, given a List, we can call get() and make use of the result. The result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected.
So having a wildcard type ensures that we can't add() to the List, with the exception of null. If you are just calling get() on the List, you know that it is at least an Object.
According to Item 28-USE BOUNDED WILDCARDS TO INCREASE API FLEXIBILITY of effective java
if a type parameter appears only once in a method declaration, replace
it with a wildcard.
Let's say you have this class hierarchy:
Fruit
Apple extends Fruit
Orange extends Fruit
...and some lists of each type of fruits:
List<Apple> apples ; and List<Orange> oranges ;
Now you want a List that can refer to any one of these lists.
So you declare List<? extends Fruit> fruits ;
You cannot use a type variable here.
Using wildcards, your code is typesafe. In
List myList;
you can add any object you want. But in:
List<?> myList;
you can only add a null.
You should only use List, without type parameter, when you need the class (List.class) or when you need to check for type (instance of List).
You're right. Technically, every time you see a wildcard at the first level in the type of a parameter, you could create a new type variable for it, and use that type variable in the place of that wildcard, and it would work the same.
However, I would argue that is much less elegant than using a wildcard. A type variable is useful for express establishing constraints between different expressions, like when there are two parameters with the same type variable, or between a parameter and return type. A type variable used in just one place in the parameter is kind of a waste -- that was exactly what wildcards are meant for -- an "anonymous" type variable that is not needed anywhere else. When you just need to express "some type", without needing to constrain it with something else, why clutter your method signature with bonus type variables?
There are also other uses of wildcards that cannot be replaced type variables. For example, consider a method public List<?> foo(). It returns some kind of list, but you don't know a list of what (and it is unsafe to add anything to it). There is no way to express that using type variables without wildcards.
Also, consider wildcards in nested type parameters: you could have a variable of type List<List<?>>, i.e. a heterogenous list whose elements can be lists of different things. This also cannot be expressed without using wildcards.
Because
you can modfify list in case of <T> list.add((T) new Object());
but you can not modify list in case of ? which ensures that list does not get modified.
compiler generate error if you add anything other than null.
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
On the other hand, given a List<?>, we can call get() and make use of the result. The result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected
More information on WildCards
One of the best uses for wildcards I found are complex nestings of Generic types.
A simple example with a list of Pair<T,E>, the wildcard makes the code shorter and more readable since everyone can see that I am only interested in the boolean value.
ArrayList<Pair<Boolean, OneOrOtherLongClassName>> pairList = ...;
for(Pair<Boolean,?> p:pairList)
{
if(p.first)count++;
}

Java Generics: List, List<Object>, List<?>

Can someone explained, as detailed as possible, the differences between the following types?
List
List<Object>
List<?>
Let me make this more specific. When would I want to use
// 1
public void CanYouGiveMeAnAnswer(List l) { }
// 2
public void CanYouGiveMeAnAnswer(List<Object> l) { }
// 3
public void CanYouGiveMeAnAnswer(List<?> l) { }
As the other posts have noted, you are asking about a Java feature called generics. In C++, this is called templates. This feature in Java is usually easier to work with than the that found in C++.
Let me answer your questions functionally (if that's not a naughty word for OO discussions).
Before generics, there were concrete classes like Vector.
Vector V = new Vector();
Vectors hold any object you give them.
V.add("This is an element");
V.add(new Integer(2));
v.add(new Hashtable());
They do this by casting all values given to it into an Object (the root of all Java classes). When you attempt to retrieve the values stored in your Vector, you need to cast the value back into the original class (if you want to do anything meaningful with it).
String s = (String) v.get(0);
Integer i = (Integer) v.get(1);
Hashtable h = (Hashtable) v.get(2);
Casting gets old fast. More than that, the compiler complains to you about unchecked casts. The most urgent problem with casting like this is that consumers of your Vector have to know the classes of its values at compile time in order to cast correctly. In cases where the producer of the Vector and the consumer of the same are completely isolated from each other (think RPC messages), this can be a fatal issue.
Enter generics. Generics attempt to create strongly typed classes to do generic operations.
ArrayList<String> aList = new ArrayList<String>();
aList.add("One");
String element = aList.get(0); // no cast needed
System.out.println("Got one: " + element);
The Design Patterns book encourages the reader to think in terms of contracts, not concrete types. There is wisdom (and code re-use) in divorcing variables from their implementing class.
With this in mind, you might think that all implementations List objects should do the same set of things: add(), get(), size(), etc. With a little reflection, you can imagine many implementations of List operations that obey the List contract in various ways (e.g. ArrayList). However, the type of data these objects deal with is orthogonal to the actions performed on them.
Put it all together and you'll see the following kinds of code frequently:
List<String> L = new ArrayList<String>();
You should read that as "L is a kind of List that deals with String objects". When you start dealing with Factory classes, it is critical to deal with contracts rather than specific implementations. Factories produce objects of various types at runtime.
Using generics is pretty easy (most of the time).
One day you may decide you want to implement your own generic class. Perhaps you want to write a new database abstraction interface that elides the differencesbetween various data stores. When you define that generic class, you will use <t> as a placeholder for the kind of object that will be manipulated by the methods.
If you are still confused, use the generic classes for List until you are comfortable. Later, you can dive into the implementation with a bit more confidence. Or you can look at the source code for the various List classes that ship with the JRE. Open source is great that way.
Have a look at the Oracle/Sun docs about generics.
Cheers.
In my own simple terms:
List
Would declare an ordinary collection, can hold any type, and will always return Object.
List<Object>
Will create a list that can hold any type of object, but can only get assigned a another List<Object>
For instance this doesn't work;
List<Object> l = new ArrayList<String>();
Of course you can add anything but only can pull Object.
List<Object> l = new ArrayList<Object>();
l.add( new Employee() );
l.add( new String() );
Object o = l.get( 0 );
Object o2 = l.get( 1 );
Finally
List<?>
Will let you assign any type, including
List <?> l = new ArrayList();
List <?> l2 = new ArrayList<String>();
This would be called collection of unknown and since the common denominator of unknown is Object you will be able to fetch Objects ( a coincidence )
The importance of unknown comes when its used with subclassing:
List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles
List<? extends Collection> l = new ArrayList<String>(); // doesn't,
// because String is not part of *Collection* inheritance tree.
I hope using Collection as the type doesn't create confusion, that was the only tree that came to my mind.
The difference here, is that l is a collection of unknow that belongs to the Collection hierarchy.
To add to the already good answers here:
Method arguments:
List<? extends Foo>
good choice if you don't intend to alter the list, and only care that everything in the list is assignable to type 'Foo'. This way, the caller can pass in a List<FooSubclass> and your method works. Usually the best choice.
List<Foo>
good choice if you intend to add Foo objects to the list in your method. The caller may not pass in a List<FooSubclass>, as you intend to add a Foo to the List.
List<? super Foo>
good choice if you intend to add Foo objects to the list, and it's not important what else is in the list (ie, you are ok getting a List<Object> that contains a 'Dog' that has nothing to do with Foo).
Method return values
just like method arguments, but with the benefits reversed.
List<? extends Foo>
Guarantees that everything in the returned List has type 'Foo'. It might be List<FooSubclass> though. Caller cannot add to the List. This is your go-to choice and the most common case by far.
List<Foo>
Just like List<? extends Foo> but also allows the caller to add to the List. Less common.
List<? super Foo>
allows the caller to add Foo objects to the List, but does not guarantee what will be returned from list.get(0)... it could be anything from Foo to Object. The only guarantee is that this won't be a list of 'Dog' or some other choice that would prevent list.add(foo) from being legal. Very rare use case.
I hope that helps. Good luck!
ps. To sum up... two questions...
do you need to add to the List? Do you care what is in the list?
yes yes - use List<Foo>.
yes no - use List<? super Foo>.
no yes - use <? extends Foo> --- most common.
no no - use <?>.
I refer you to the excellent Java Generics tutorial, and the "advanced" Generics tutorial, both available from Sun Microsystems. Another great resource is the Java Generics and Collections book.
I will try to answer this in detail. Before generics we were having only List (a raw list) and it can hold almost anything we can think of.
List rawList = new ArrayList();
rawList.add("String Item");
rawList.add(new Car("VW"));
rawList.add(new Runnable() {
#Override
public void run() {
// do some work.
}
});
The major problem with the raw list is when we want to get any element out of such list it can only guarantee that it would be Object and for that reason we need to use casting as:
Object item = rawList.get(0); // we get object without casting.
String sameItem = (String) rawList.get(0); // we can use casting which may fail at runtime.
So conclusion is a List can store Object (almost everything is Object in Java) and always returns an Object.
Generics
Now lets talk about generics. Consider the following example:
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
stringsList.add(new Car("Fiat")); //error
String stringItem = stringsList.get(0);
In the above case we cannot insert anything other than String in stringsList as Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. And we get error when we try to insert a Car instance in it. Also it eliminates cast as you can check when we invoke get method. Check this link for understanding why we should use generics.
List<Object>
If you read about type erasure then you will understand that List<String>, List<Long>, List<Animal> etc. will be having different static types at compile time but will have same dynamic type List at run time.
If we have List<Object> then it can store only Object in it and almost everything is Object in Java. So we can have:
List<Object> objectList = new ArrayList<Object>();
objectList.add("String Item");
objectList.add(new Car("VW"));
objectList.add(new Runnable() {
#Override
public void run() {
}
});
Object item = objectList.get(0); // we get object without casting as list contains Object
String sameItem = (String) objectList.get(0); // we can use casting which may fail at runtime.
It seems List<Object> and List are same but actually they are not. Consider the following case:
List<String> tempStringList = new ArrayList<>();
rawList = tempStringList; // Ok as we can assign any list to raw list.
objectList = tempStringList; // error as List<String> is not subtype of List<Obejct> becuase generics are not convariant.
You can see we can assign any list to raw list and major reason for that is to allow backward compatibility. Also List<String> will be converted to List at run time due to type erasure and assignment will be fine anyways.
But List<Object> means it can only refer to a list of objects and can also store objects only. Even though String is subtype of Object we cannot assign List<String> to List<Object> as generics are not covariant like arrays. They are invariant. Also check this link for more. Also check the difference between List and List<Object> in this question.
List<?>
Now we are left with List<?> which basically means list of unknown type and can refer to any list.
List<?> crazyList = new ArrayList<String>();
List<String> stringsList = new ArrayList<>();
stringsList.add("Apple");
stringsList.add("Ball");
crazyList = stringsList; // fine
The character ? is known as wildcard and List<?> is a list of unbounded wildcard. There are certain points to observe now.
We cannot instantiate this list as the following code will not compile:
List<?> crazyList = new ArrayList<?>(); // any list.
We can say a wildcard parameterized type is more like an interface type as we can use it to refer to an object of compatible type but not for itself.
List<?> crazyList2 = new ArrayList<String>();
We cannot insert any item to it as we don't know what actually the type would be.
crazyList2.add("Apple"); // error as you dont actually know what is that type.
Now question arises When would I want to use List<?>?
You can think of this as a read-only list where you don't care about the type of the items. You can use it to invoke methods like returning the length of the list, printing it etc.
public static void print(List<?> list){
System.out.println(list);
}
You can also check the difference between List, List<?>, List<T>, List<E>, and List<Object> here.
Simplest explanation which is not "RTFM":
List
Will generate lots of compiler warnings, but is mostly equivalent to:
List<Object>
While:
List<?>
basically means its something generic, but you don't know what the generic type is. Its great for getting rid of compiler warnings when you cant modify the return types of other things that just returned List. Its much more useful in the form:
List<? extends SomeOtherThing>
The shortest possible explanation is: The second item is a list that can hold any type, and you can add objects to it:
List<Object>
The first item you list is treated as essentially equivalent to this, except you will get compiler warnings because it is a "raw type".
List
The third is a list that can hold any type, but you cannot add anything to it:
List<?>
Basically, you use the second form (List<Object>) when you truly have a list that can contain any object and you want to be able to add elements to the list. You use the third form (List<?>)when you receive the list as a method return value and you will iterate over the list but never add anything to it Never use the first form (List) in new code compiling under Java 5 or later.
I'd put it this way: While List and List<Object> can contain any type of objects, List<?> contains elements of an unknown type, but once that type is captured, it can only contain elements of that type. Which is why it is the only type safe variant of those three, and therefore generally preferable.
To complement the tutorials mentioned by Rob, here's a wikibook explaining the topic:
http://en.wikibooks.org/wiki/Java_Programming/Generics
Edit:
No restrictions on type of items in list
Items in list must extend Object
Wildcard used by itself, so it matches anything
Would it be naive of me to conclude at this point that there's hardly any/no difference at all?
When would I want to use
public void CanYouGiveMeAnAnswer( List l ){}
When you cant to do all the casting your self.
When would I want to use
public void CanYouGiveMeAnAnswer( List l<Object> ){}
When you want to restrict the type of the List. For instance, this would be an invalid argument.
new ArrayList<String>();
When would I want to use
public void CanYouGiveMeAnAnswer( List l<?> ){}
Mostly never.
List, List<?>, and List<? extends Object> are the same thing. The second is more explicit. For a list of this type, you cannot know what types are legal to put into it, and you don't know anything about the types you can get out of it, except that they will be objects.
List<Object> specifically means that the list contains any sort of object.
Let's say we make a list of Foo:
List<Foo> foos= new ArrayList<Foo>();
It is not legal to put a Bar into foos.
foos.add(new Bar()); // NOT OK!
It is always legal to put anything into a List<Object>.
List<Object> objs = new ArrayList<Object>();
objs.add(new Foo());
objs.add(new Bar());
But you mustn't be allowed to put a Bar into a List<Foo> - that's the whole point. So that means that this:
List<Object> objs = foos; // NOT OK!
is not legal.
But it's ok to say that foos is a list of something but we don't know specifically what it is:
List<?> dontKnows = foos;
But that then means that it must be prohibited to go
dontKnows.add(new Foo()); // NOT OK
dontKnows.add(new Bar()); // NOT OK
because the variable dontKnows does't know what types are legal.
List < Object > is meant to pass input type parameter of an Object. While List < ? > represents Wildcard type. The wildcard < ? > is of Unknown parameter type. The wildcard cannot be used as a type argument for a generic method and cannot be used to create a generic instance of a class. Wildcard can be used to extend a subtype class, List < ? extends Number >. To relax the restriction of an Object type and in this case to relax "Number" Object type.
In terms of List functionality differences, the other responses already answered this question. In terms of applicable rules of Java generics, it's a complicated topic. I wrote an in-depth article about Java generics rules, this is the link: https://medium.com/#royalilin/java-generics-rules-1d05de86e9cb

Categories

Resources