java generics bug?

Discussion in 'Java' started by robertjparks@gmail.com, Aug 7, 2007.

  1. Guest

    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
     
    , Aug 7, 2007
    #1
    1. Advertising

  2. Daniel Pitts Guest

    On Aug 7, 8:48 am, 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
    > 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.
     
    Daniel Pitts, Aug 7, 2007
    #2
    1. Advertising

  3. 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
    > 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
     
    Thomas Hawtin, Aug 7, 2007
    #3
  4. Muggle Guest

    On Aug 7, 11:48 am, 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
    > 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.
     
    Muggle, Aug 7, 2007
    #4
  5. Guest

    On Aug 7, 12:57 pm, Muggle <> wrote:
    > On Aug 7, 11:48 am, 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
    > > 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.


    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.
     
    , Aug 7, 2007
    #5
  6. Guest

    On Aug 7, 12:02 pm, Daniel Pitts <> wrote:
    > On Aug 7, 8:48 am, 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
    > > 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.



    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
     
    , Aug 7, 2007
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    4
    Views:
    838
    Chris Smith
    Aug 27, 2004
  2. Juergen Berchtel
    Replies:
    1
    Views:
    6,038
    John C. Bollinger
    May 20, 2005
  3. Royan
    Replies:
    8
    Views:
    765
    Patricia Shanahan
    Feb 15, 2008
  4. Vikram
    Replies:
    4
    Views:
    537
    Vikram
    Jun 13, 2008
  5. Soul
    Replies:
    0
    Views:
    535
Loading...

Share This Page