Reputation: 7828
In the official tutorials #Wildcard Capture and Wildcard Capture and Helper Methods and its easy-understanding demos as:
public class WildcardFixed {
void foo(List<?> i) {
fooHelper(i);
}
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
}
I've also read some posts in StackOverflow discussing Wildcard Capture but when I try to use it as
public static <T> void addToSet(Set<T> s, T t) {
// I was hoping the type inference will infer the T to String
}
private static <T> Set<T> setWrapper(Set<T> theSet) {
return theSet;
}
public static void testUnboundedWildcard() {
Set<?> unknownSet = new HashSet<String>();
// ------> here lies the compile error <-------
HelloWorld.<String>addToSet(setWrapper(unknownSet), "abc");
}
The compile error shows
Error:(52, 47) java: incompatible types: inferred type does not conform to equality constraint(s)
inferred: java.lang.String
equality constraints(s): java.lang.String,capture#1 of ?
I thought I can capture the wildcard and do things as generic method
but I was completely wrong.
Upvotes: 1
Views: 107
Reputation: 262494
why exactly we need it? any specific scenarios can be found?
You can use it when you only need to work with the base type and really don't care about the generic type.
For example, you could have a method
boolean hasTooManyElements(Collection<?> data){
return data.size() > 100;
}
Without a wildcard you would have to (without good reason) limit this method to work only on Collections of specific types.
Note that a wildcard can still be bounded:
boolean hasEmptyText(Collection<? extends CharSequence> data) {
return data.exists(x -> x.isEmpty());
// you can call `isEmpty` because of the bounded wildcard
}
You could also express this by making your method generic (but there is not much point if you are not going to use the type T
anywhere).
<T> boolean hasTooManyElements(Collection<T> data);
You want to have the <T>
in cases like this:
// limit the return type
<T> T getRandomElement(Collection<T> data);
// or, more flexible
<T> T getRandomElement(Collection<? extends T> data);
// make sure the two inputs have the same generic type
<T> boolean areEqual(Collection<T> one, Collection<T> two);
Upvotes: 2