Hearen
Hearen

Reputation: 7828

Why we need Wildcard Capture?

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.

My Confusion

  1. why my code using Wildcard Capture cannot work?
  2. if it just cannot work then why exactly we need it? any specific scenarios can be found?

Upvotes: 1

Views: 107

Answers (1)

Thilo
Thilo

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

Related Questions