Java Forum / General / August 2007
java generics bug?
robertjparks@gmail.com - 07 Aug 2007 16:48 GMT To sum up the problem in one sentence I would say that java does not allow wildcards in a nested value of a Map in a method. I am using jdk1.6.0_02 on windows.
<code> public class Whatever{ public static void printOneDimension(Map<String,?> map){ for(String k1:map.keySet())System.out.println(k1); }
public static void printTwoDimensions(Map<String,Map<String,?>> map){ for(String k1:map.keySet()){ for(String k2:map.get(k1).keySet()){ System.out.println(k1+","+k2); } } }
public static void main(String[] args){ Map<String,String> m1=new HashMap<String,String>(); m1.put("a",null); m1.put("b",null); printOneDimension(m1);
Map<String,Map<String,String>> m2=new HashMap<String,Map<String,String>>(); m2.put("x",null); m2.put("y",null); printOneDimension(m2);
//printTwoDimensions(m2); } </code>
When I run it with printTwoDimensions() comment out, I get the following output as expected: b a y x
When I uncomment the call to printTwoDimensions(m2) gives the compilation error:
printTwoDimensions(java.util.Map<java.lang.String,java.util.Map<java.lang.String,?
>>) in StructUtils.MapUtils cannot be applied to (java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>) printTwoDimensions(m2);
Java can compile printTwoDimensions fine, I just can't figure out how to call it without a compilation error.
Although I don't think I should have to I tried casting to the wildcard just to see what would happen:
<code> printTwoDimensions((Map<String,Map<String,?>>)m2); </code>
And I got this compilation error message:
inconvertible types found : java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>> required: java.util.Map<java.lang.String,java.util.Map<java.lang.String,?>> printTwoDimensions((Map<String,Map<String,?>>)m2);
Please let me know if you think is is a bug or if I am missing something.
Thanks, Rob
Daniel Pitts - 07 Aug 2007 17:02 GMT On Aug 7, 8:48 am, robertjpa...@gmail.com wrote:
> To sum up the problem in one sentence I would say that java does not > allow wildcards in a nested value of a Map in a method. I am using [quoted text clipped - 70 lines] > Thanks, > Rob I think what you want to do is:
public static <T> void printOneDimension(Map<String,T> map){
Hope this helps.
Daniel.
robertjparks@gmail.com - 07 Aug 2007 18:51 GMT > On Aug 7, 8:48 am, robertjpa...@gmail.com wrote: > [quoted text clipped - 80 lines] > > Daniel. Excellent! This worked. I guess I need to learn more about this T notation. For anyone following the thread here is the final solution:
public static void printOneDimension(Map<String,?> map){ for(String k1:map.keySet())System.out.println(k1); } public static <T> void printTwoDimensionsNew(Map<String,Map<String,T>> map){ for(String k1:map.keySet()){ for(String k2:map.get(k1).keySet()){ System.out.println(k1+","+k2); } } } public static void main(String[] args){ Map<String,String> m1=new HashMap<String,String>(); m1.put("a",null); m1.put("b",null); printOneDimension(m1); Map<String,Map<String,String>> m2=new HashMap<String,Map<String,String>>(); m2.put("x",m1); m2.put("y",m1); printOneDimension(m2); printTwoDimensionsNew(m2);
}
Here is the output: b a y x y,b y,a x,b x,a
Thanks, Rob
Thomas Hawtin - 07 Aug 2007 17:09 GMT > To sum up the problem in one sentence I would say that java does not > allow wildcards in a nested value of a Map in a method. I am using [quoted text clipped - 8 lines] > public static void printTwoDimensions(Map<String,Map<String,?>> > map){ What if I were to insert the line:
map.put("oops", new java.util.HashMap<String, Integer>());
What one should be able to do is use:
public static <V> void printTwoDimensions( Map<String,Map<String,V>> map ) {
(Disclaimer: I haven't so much as compiled the code.)
Tom Hawtin
Muggle - 07 Aug 2007 17:57 GMT On Aug 7, 11:48 am, robertjpa...@gmail.com wrote:
> To sum up the problem in one sentence I would say that java does not > allow wildcards in a nested value of a Map in a method. I am using [quoted text clipped - 70 lines] > Thanks, > Rob Change the definition of m2 to Map<String,Map<String,?>> m2=new HashMap<String,Map<String,?>>();
Your method printTwoDimensions expects a map of Map<String,?>. A map of Map<String,?> is not the same as a map of Map<String,String>. (In terms of values, that is)
In the case of printOneDimension, it expects a map of (any) unknown type. So it would work with a map of String or a map of map of String.
robertjparks@gmail.com - 07 Aug 2007 18:44 GMT > On Aug 7, 11:48 am, robertjpa...@gmail.com wrote: > [quoted text clipped - 83 lines] > In the case of printOneDimension, it expects a map of (any) unknown > type. So it would work with a map of String or a map of map of String. I changed my code as follows:
Map<String,String> m1=new HashMap<String,String>(); m1.put("a",null); m1.put("b",null); printOneDimension(m1); Map<String,Map<String,?>> m2=new HashMap<String,Map<String,?
>>(); //Map<String,Map<String,String>> m2=new HashMap<String,Map<String,String>>(); m2.put("x",m1); // Note I updated this to use m1 instead of null m2.put("y",m1); // since you cannot print null. printOneDimension(m2);
printTwoDimensions(m2)
And it compiled and printed results as expected:
b a y x y,b y,a x,b x,a
That said, I don't want to declare the m2 with ? as a value and I don't understand why I should have to.
If I declare m2 with the ? as shown, I have no way to get it back to a Map<String,Map<String,String>>. Even if casting it back worked, it would be a pain and I don't see why it is necessary.
My understanding of wildcard '?' is that it can represent any type but it limits your ability to perform operations that require knowing the type. This works fine with the function printOneDimension() as the map parameter is declared as a Map<String,?> and we never accesses the ? (value) portion of the declaration.
By this same logic, printTwoDimensions() only accesses known parts of the Map<String,Map<String,?>>. The compiler should be able to safely determine that it can accept a Map<String,Map<String,Integer>> since it never accesses the value of the nested Map.
I don't really need to solve this problem so much as I want to understand generics better. Do you guys agree that javac "should" be able to accept a Map<String, Map<String, ANYTHING>> as a param to printTwoDimensions? If not why do you disagree.
Thanks, Rob.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|