Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing nested type parameters and wildcards in Java

Tags:

java

generics

Why does trying to compile

public class GenericsFail {
    public static void main(String[] args) {
        accept(new HashMap<String, List<String>>());
    }

    public static void accept(Map<String, List<?>> multiMap) {}
}

give the error

GenericsFail.java:7: error: method accept in class GenericsFail cannot be applied to given types;
                accept(new HashMap<String, List<String>>());
                ^
  required: Map<String,List<?>>
  found: HashMap<String,List<String>>
  reason: actual argument HashMap<String,List<String>> cannot be converted to Map<String,List<?>> by method invocation conversion

The wildcard is only allowed if it's not nested inside List.

like image 492
hertzsprung Avatar asked Oct 24 '12 19:10

hertzsprung


People also ask

Can wildcard types be replaced by any type?

Due to extensive capture conversion, in most places, compiler treats wildcards as if they are type variables. Therefore indeed programmer can replace wildcard with type variables in such places, a sort of manual capture conversion.

What is a wildcard parameterized type?

In the Java programming language, the wildcard ? is a special kind of type argument that controls the type safety of the use of generic (parameterized) types. It can be used in variable declarations and instantiations as well as in method definitions, but not in the definition of a generic type.

What is the symbol for a wildcard type parameter in Java?

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).

Why do we need wildcards in Java?

Wildcards in Java are basically the question marks which we use in generic programming, it basically represents the unknown type. We use Java Wildcard widely in situations such as in a type of parameter, local variable, or field and also as a return type.


1 Answers

The reason is that the ? in List<?> could be "anything", but a different "anything" in each Map entry. That is, it would accept a List<String> in one entry, and a List<Integer> in another.

But you are passing in a Map that has the same type of List in every entry, so the type is not bound in the same way or the to same degree for freedom.

The "fix" is to lock the type to a specific type, but still being "anything" - just the same "anything* in every entry, by typing the method:

public static <T> void accept(Map<String, List<T>> multiMap) // complies

or if your method really doesn't need to know which type, use a wildcard to wrap the type:

public static void accept(Map<String, ? extends List<?>> multiMap) // compiles

This last version works because the type of the list, although being a wildcard, is fixed to an unknown, but consistent, type when called.


I find the typed version easier to read (and code), and the type is there for use should you decide later that your method needs to know the type.

like image 87
Bohemian Avatar answered Oct 04 '22 21:10

Bohemian