java generics bug?

R

robertjparks

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,?(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
 
D

Daniel Pitts

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

I think what you want to do is:

public static <T> void printOneDimension(Map<String,T> map){


Hope this helps.

Daniel.
 
T

Thomas Hawtin

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){

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
 
M

Muggle

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

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.
 
R

robertjparks

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);


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 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:

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

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.

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,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.
 
R

robertjparks

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);


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 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:

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

I think what you want to do is:

public static <T> void printOneDimension(Map<String,T> map){

Hope this helps.

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top