Map.get(Object o) vs Map.get(K k) ?

If some one can explain why Map interface has some of the methods (using keys and values) are uses K/V and others still use Object?

example

I can do some thing like this

Map<Long,String> map = new TreeMap<Long,String>();

map.containsValue(new Long(0)); /*can compile , but runtime exception*/

map.containsKey("1"); /*can compile , but runtime exception*/

String v = map.get("1");

//map.put("1",""); /*Can't compile*/

IMHO, this is not a good idea becuase it renders "genercs" useless, I still get nasty class cast exceptions at run time.

If some one can explain reasons for this design decision.

thanks

haroon

[697 byte] By [haroonzca] at [2007-10-2 5:45:55]
# 1

> Map<Long,String> map = new TreeMap<Long,String>();

> map.containsValue(new Long(0)); /*can compile , but

> runtime exception*/

Shouldn't be an exception, should just return false. Why not try it and see?

> map.containsKey("1"); /*can compile , but runtime

> exception*/

Are you sure? What's the exception?

> String v = map.get("1");

> //map.put("1",""); /*Can't compile*/

Because "1" is not a Long. You're not allowed to put a String key into a Map that requires a Long key.

>

> IMHO, this is not a good idea becuase it renders

> "genercs" useless, I still get nasty class cast

> exceptions at run time.

>

> If some one can explain reasons for this design

> decision.

No, it doesn't render generics useless. Generics are for compile-time type safety. That's why you can't put a String into a map where it expects a long.

However, there's no type-safety problem with saying "get me this string" or "does it contain this string?" when it can only contain longs. The answer will just be null or false, respectively.

targaryena at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 2

First, thanks for the quick reply :)

I tried it and it worked fine as you explaind BUT if map is empty

examples are

String key="146564";

TreeMap<String, String> map = new TreeMap<String, String>();

//map.put(key,key); /*If you uncomment this line you will get Exception*/

map.containsValue(new Long(key)); /*can compile */

map.containsKey(new Long(146564)); /*can compile */

String v = map.get("1");

//map.put(new Long(1), "");/*Can't compile*/

System.out.println("done ");

Here is exception if you uncomment line 3

Exception in thread "main" java.lang.ClassCastException: java.lang.String

at java.lang.Long.compareTo(Long.java:34)

at java.util.TreeMap.compare(TreeMap.java:1093)

at java.util.TreeMap.getEntry(TreeMap.java:347)

at java.util.TreeMap.containsKey(TreeMap.java:204)

atTestClass.main(TestClass.java:27)

haroonzca at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 3

I belive it is a bug in treeMap implementation, becuase HashMap works fine, I tried following and it works

String key="146564";

HashMap<String, String> map = new HashMap<String, String>();

map.put(key,key);

map.containsValue(new Long(key)); /*can compile */

map.containsKey(new Long(146564)); /*can compile */

String v = map.get("1");

//map.put(new Long(1), "");/*Can't compile*/

but changing line two to

TreeMap<String, String> map = new TreeMap<String, String>();

causes runtime CalssCast exception

haroonzca at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 4
> but changing line two to> TreeMap<String, String> map = new TreeMap<String,> String>();> > causes runtime CalssCast exceptionOn which line(s)?
targaryena at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 5

> I belive it is a bug in treeMap implementation,

No, it's not a bug. A TreeMap sorts its keys according to their natural sort order (unless you specify a customized Comparator when you create the map, which you don't). When you do this:

map.containsKey(new Long(146564));

the map will use the compareTo method to compare the present keys with the key you are asking for. You'll end up passing a String to Long's compareTo method, which results in a ClassCastException.

Note that this really has nothing to do with generics.

happy_hippoa at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 6
Oooohhhhh.....That makes sense. Perfectly obvious now that you say it, but it would have had me scratching my head for a while, no doubt. I'd have to run the code and see the stack trace.
targaryena at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 7

>No, it's not a bug. A TreeMap sorts its keys according to their natural sort order

ok if you say so ....

>Note that this really has nothing to do with generics.

I agree with that

But, end result is TreeMap does not fit in this claim

"Because the program compiles without warnings, we can state with

certainty that it will not throw a ClassCastException at run time.

The net effect of using generics, especially in large programs,

is improved readability and robustness."

[url]http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html[/url]

So either it is a lack of interface constraint in Map

, whic should have specified

containsKey(K k)

rahter than

containsKey(Object k)

or TreeMap

just "assumes" some thing that it should not. Being a client of TreeMap<K,V>

and above mentioned documents I don't expect any method of TreeMap to throw a runtime ClassCastException

becuase, type of given Key does not match declaration of TreeMap<K,V>. I thought generics were designed specifically to give this piece of mind to clients of collections framework. If I still need to remember types of <key,value> pairs in a TreeMap, we have not moved type checking to compile time, it is still checked at run time (at least for some methods in some classes, under certain conditions)

I believe it works for HashMap

becuase HashMap will use hashCode()

, a method available from Object

and over ridden by most classes, and not because implementation of HasMap was different from TreeMap in this regard

haroonzca at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 8

>

> or TreeMap

just "assumes" some thing

> that it should not.

It does "assume" something, and it states very clearly what it assumes in its API (the API for SortedMap, actually, which TreeMap extends):

"All keys inserted into a sorted map must implement the Comparable interface (or be accepted by the specified comparator). Furthermore, all such keys must be mutually comparable: k1.compareTo(k2) (or comparator.compare(k1, k2)) must not throw a ClassCastException for any elements k1 and k2 in the sorted map. Attempts to violate this restriction will cause the offending method or constructor invocation to throw a ClassCastException."

Again, note that you have exactly the same situation without generics. The following code also compiles fine, but throws a ClassCastException when you run it:

Map map = new TreeMap();

map.put("abc", "xyz");

map.containsKey(Long.valueOf(5));

whereas this code both compiles and runs:

Map map = new HashMap();

map.put("abc", "xyz");

map.containsKey(Long.valueOf(5));

I understand your confusion, but you'll just have to accept that a sorted map will behave different from a hash map, say, in this regard.

happy_hippoa at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 9

> >No, it's not a bug. A TreeMap sorts its keys

> according to their natural sort order

> ok if you say so ....

>

> >Note that this really has nothing to do with

> generics.

> I agree with that

>

> But, end result is TreeMap does not fit in this

> claim

> "Because the program compiles without warnings, we

> we can state with

> certainty that it will not throw a

> ow a ClassCastException at run time.

I wouldn't take that as "generics prevent all CCE's."

If you look at TreeMap's docs, you'll see that containtsKey takes Object, not K.

So it behaves as documented.

Now, it may be that there was a good reason for making it that way, or it may be a design flaw. I really don't know.

You might want to take this over to this site's Generics forum. I know at least one of Sun's generics implementors answers questions there.

targaryena at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 10

> "All keys inserted into a sorted map must implement the Comparable interface

Thanks for pointing to this, however, looks like it refers to "all inserted keys" and not "All arguments expected to be used as keys", and may that's exectly why put(K k,V v) forces a compile time check so that we can satisfy "All inserted keys ...." constraints on SortedMaps.

My confusion is that i fail to understand reasons behind such a design decision that makes implementers of generics not so orthognal.

haroonzca at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 11

> "All keys inserted into a sorted map must implement the Comparable interface

Thanks for pointing to this, however, looks like it refers to "all inserted keys" and not "All arguments expected to be used as keys", and may that's exectly why put(K k,V v) forces a compile time check so that we can satisfy "All inserted keys ...." constraints on SortedMaps.

My confusion is that i fail to understand reasons behind such a design decision that makes implementers of generics not so orthognal.

haroonzca at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 12
> Now, it may be that there was a good reason for making it that way, or it may be a design flaw. I really don't know.That is exectly what I wanted to know, thanks
haroonzca at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 13

> > Now, it may be that there was a good reason for

> making it that way, or it may be a design flaw. I

> really don't know.

>

> That is exectly what I wanted to know, thanks

You're welcome, I guess, but I don't think I actuall answered anything, only redirected the question toward a more "core" issue. :-)

targaryena at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 14

Consider the following code:

import java.util.*;

public class Test

{

public static void main(String[] args)

{

Map<TreeMap><?, ?>, Integer> mapA = new HashMap<TreeMap><?, ?>, Integer>();

Map<? extends Map<?, ?>, ? extends Number> mapB = mapA;

TreeMap<String, String> temp = new TreeMap<String, String>();

temp.put("test", "test");

mapA.put(temp, 10);

HashMap<String, String> look = new HashMap<String, String>();

look.put("test", "test");

System.out.println(mapB.get(look));

}

}

When run this code outputs: 10

Now, comment out the import and add the following to the java file:

interface Map<K, V>

{

public void put(K k, V v);

public V get(K k);

}

class HashMap<K, V> implements Map<K, V>

{

java.util.HashMap<K, V> map = new java.util.HashMap<K, V>();

public void put(K k, V v)

{

map.put(k, v);

}

public V get(K k)

{

return map.get(k);

}

}

class TreeMap<K, V> implements Map<K, V>

{

java.util.TreeMap<K, V> map = new java.util.TreeMap<K, V>();

public void put(K k, V v)

{

map.put(k, v);

}

public V get(K k)

{

return map.get(k);

}

}

You see that the code will no longer compiles. Note that the getMethod becomes completely useless when the K type is a capture. The only allowed value to get would be null for this case.

I think this is a judicous use of generics. I think there is greater danger in the over-genericizing of types than in under-genericizing them. Generic declarations should not prevent proper usage of the class.

dubwaia at 2007-7-16 1:55:45 > top of Java-index,Core,Core APIs...
# 15
I do nor understand your demo code ... if you code mapB.put(look,20)it won't compile either ....can't we get a simple (or step by step) rationale on this one?thanks
amadea at 2007-7-20 18:42:06 > top of Java-index,Core,Core APIs...