Java Generics - 5. Wildcards
This is part 5 of the 9 part series on Java Generics
Prev Topic
|
Topics
1. Introduction
2. Bounding
8. Target Types
|
|
Java Generics - Wildcards
“?” wildcard in Java, means “any”. If a method takes in a
declaration with <?>, it means it can take any type. Say you’d like to
perform a certain operation which applies to all types (usually for a library
class) , then this wildcard can be handy. Say you want a method which gives
back the size of the list, but you also want to handle ‘null’ scenarios. Then
you could write the code as:
public static int getSize(List<?> list){
return list == null ? 0 : list.size();
}
|
In fact this method is not different with the one declared
below.
public static <E> int getSize(List<E> list){
return list == null ? 0 : list.size();
}
|
Then which one we should use? Answer would be any one you
like. My personal preference is the second one, because first, it appears more
clear and second, because while referring individual elements of List, I can
use E directly without defining it once again. It appears more elegant.
Consider the two methods below. They count how many elements are greater than
the given number. They essentially do the same thing. Again it’s a matter of
choice and you can use any style over the other one.
Note that the method getSize(List<E> list) or getSize(List<?>
list) list is different from getSize(List<Object> list).
The latter takes in only the List of Object and not any type
of List.
public static int countGT2(List<? extends Number> nList, int num){
int c = 0;
for (Number e : nList){
if (e.intValue() > num)
c++;
}
return c;
}
public static <E extends Number> int countGT1(List<E> nList, int num){
int c = 0;
for (E e : nList){
if (e.intValue() > num)
c++;
}
return c;
}
|
Then what is the use of an additional wildcard “?”,
in the java programming language? Maybe it wasn’t needed at all! Well it is
most useful in declaring and referring variables, something we will explore in
the coming sections.
Java goes one step farther and checks for as many type
checks as possible during compilation. For instance it does instanceof
checks for classes, but not interfaces.
public <F extends Mango> void foo(F f){
if (f instanceof Fruit){
// do something
}
if (f instanceof Alphonso){
// do something
}
if (f instanceof Object){
// do something
}
if (f instanceof Map<?, ?>){
// do something
}
// compiler error
// Incompatible
conditional operand types F and Wheat
if (f instanceof Wheat){
// do something
}
}
|
In the method above, F extends Mango, so the instanceof
checks are valid for Fruit too as Mango is a fruit. It is
also valid for Alphonso which is a type of Mango. The java compiler
does not check for interfaces so any interface check (in this case check for Map<?,?>)
will not throw any error. Wheat for instance does not fall
under the Mango hierarchy and so the compiler would throw the error - Incompatible
conditional operand types F and Wheat. It will also throw error for Grape
and Shiraz
as they are not a part of Mango hierarchy.
Prev Topic
|
Topics
1. Introduction
2. Bounding
8. Target Types
|
|
Comments
Post a Comment