Reputation: 513
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 ArrayList
s:
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 Object
s I use parametrized types (much more elegant I think).
So, the main question remains: Why do we need wildcards?
Upvotes: 16
Views: 781
Reputation: 7523
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.
Upvotes: 4
Reputation: 15656
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++;
}
Upvotes: 1
Reputation: 19185
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 callget()
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
Upvotes: 1
Reputation: 122429
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.
Upvotes: 2
Reputation: 627
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".
Upvotes: 11
Reputation: 13151
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.
Upvotes: 5
Reputation: 143846
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.
Upvotes: 7
Reputation: 9159
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).
Upvotes: 2