Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / August 2007

Tip: Looking for answers? Try searching our database.

java generics bug?

Thread view: 
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 Magazines

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

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.