Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The type T is not generic; it cannot be parameterized with arguments <?> error in a generic function

I want to create a generic function that takes any Map & a String key, if the key is not present in the map, then it should create a new instance of the Value Type (which is passed) & put it in the map & then return it.

Here is my implementation

public <T> T getValueFromMap(Map<String, T> map, String key, Class<T> valueClass){
    T value = map.get(key);
    if (value == null){
        try {
            value = valueClass.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        map.put(key, value);
    }
    return value;
}

It works if I use it with a normal (not generic) List as the value type,

Map<String,List> myMap;
List value = getValueFromMap(myMap, "aKey", List.class) //works

but not with generic type lists

Map<String,List<String>> myMap;
List<String> value = getValueFromMap(myMap, "aKey", List.class) //does not work

Also if I try to make Map<String, T> map parameter generic by changing it to Map<String, T<?>> it complains that the type T is not generic; it cannot be parameterized with arguments <?>

Can the generic parameters be themselves made generic?

Is there any way to create function with above mentioned requirements?

~Update

Thanks for all the insightful answers everyone.

I have verified that the accepted solution works for any value type with this code

    Map<String, Map<String, List<String>>> outer = 
            new HashMap<String, Map<String,List<String>>>();

    Map<String, List<String>> inner = getValueFromMap(outer, "b", 
            (Class<Map<String, List<String>>>)(Class<?>)HashMap.class);

    List<String> list = getValueFromMap(inner, "a", 
            (Class<List<String>>)(Class<?>)ArrayList.class);
like image 522
Sumit Jain Avatar asked Oct 25 '12 09:10

Sumit Jain


1 Answers

You need most specific types which is String in your case. List.class returns you Class<List<?>> in your case you need specific type so you will need to add cast Class<List<String>>

 Map<String,List<String>> myMap = new HashMap<String, List<String>>();;
 List<String> value = getValueFromMap(myMap, "aKey",
           (Class<List<String>>)(Class<?>)ArrayList.class) ;

Now if you invoke method like below

 getValueFromMap(myMap, "aKey",      List.class) 
                ^^^T is List<String>  ^^^ T is List<?> wild char since List.class
                                          will return you Class<List<?>>

So your defination of T is causing confusion to Compiler so you are getting compile error.

You can not create instance of List.class since it is interface you will need implemention class of it so call method with ArrayList.class

like image 164
Amit Deshpande Avatar answered Sep 20 '22 13:09

Amit Deshpande