This week's book giveaways are in the Java EE and JavaScript forums.
We're giving away four copies each of The Java EE 7 Tutorial Volume 1 or Volume 2(winners choice) and jQuery UI in Action and have the authors on-line!
See this thread and this one for details.
The moose likes Java in General and the fly likes Duplicate keys in Map Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of The Java EE 7 Tutorial Volume 1 or Volume 2 this week in the Java EE forum
or jQuery UI in Action in the JavaScript forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Duplicate keys in Map" Watch "Duplicate keys in Map" New topic
Author

Duplicate keys in Map

Ayan Dutta
Ranch Hand

Joined: Oct 16, 2005
Posts: 94
Can I customize the Java Map (by overriding hashcode or equal etc )so that it allows duplicate keys ?

say if do something like
map.put("a","test1");
map.put("a","test2");

then the map output will be
{a=test1,a=test2}

Can it be done ?
Regards,
Ayan
Paul Sturrock
Bartender

Joined: Apr 14, 2004
Posts: 10336

Why do this? Would you not be better using some sort of Value Object/DTO and a List? What are you trying to achieve?


JavaRanch FAQ HowToAskQuestionsOnJavaRanch
Ayan Dutta
Ranch Hand

Joined: Oct 16, 2005
Posts: 94
Just for a test , I want To do this .To see whether it can be done or not .
Regards ,
Ayan
Paul Sturrock
Bartender

Joined: Apr 14, 2004
Posts: 10336

You would have to implement your own Map I think, and you implementation would basically be a List. All the Sun provided implementations tend to use equality of the Object you use as a key to ultimately decide whether an object is added to the Map or replaces an existing entry. You could maybe override the equals and hashCode methods for whatever Object you use as a key so equality is ultimately done with object references, not object value. This won't work for Strings though, and isn't changing the functionality of the Map itself.
[ November 01, 2006: Message edited by: Paul Sturrock ]
Ådne Brunborg
Ranch Hand

Joined: Aug 05, 2005
Posts: 208
public interface Map

An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.

java.util.Map


It cannot be done. If you implement something that does, it will not be a Map. It really is that simple.


Entia non sunt multiplicanda praeter necessitatem
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24183
    
  34

To provide a different perspective: I do this all the time, although I don't try to preserve the Map interface.

Create a class with has a Map<Object, ArrayList> as a member. Implement a put(key, value) method which checks whether a key exists, and if not, adds the value to an ArrayList and puts the key, list pair into the Map; or if it does, then just adds the value to the existing List. Then your get(key) method would return a List, and you'd implement whatever other methods you felt were useful.


[Jess in Action][AskingGoodQuestions]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
You can also find something very similar to what EFH describes in Jakarta Commons Collections, namely the MultiValueMap. In this case they do implement Map, but change its semantics so that each key can have multiple values. This can lead to problems if you attempt to use the MultiValueMap in a context that assumes a normal Map. I'm not sure why they implemented Map here - there may be some situation where that makes things easier, but I can't think of one. Then again I don't think I'd have much problem with simply not using it that way. Aside from this apparent mistake (and aside from the fact it's not generics-friendly), MultiValueMap may be convenient as an already-existing implementation.
[ November 01, 2006: Message edited by: Jim Yingst ]

"I'm not back." - Bill Harding, Twister
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Originally posted by Ernest Friedman-Hill:
To provide a different perspective: I do this all the time, although I don't try to preserve the Map interface.

Create a class with has a Map<Object, ArrayList> as a member. Implement a put(key, value) method which checks whether a key exists, and if not, adds the value to an ArrayList and puts the key, list pair into the Map; or if it does, then just adds the value to the existing List. Then your get(key) method would return a List, and you'd implement whatever other methods you felt were useful.


Yeah, but that seems like needlessly breaking the Map contract. If you're going to break it, why bother implementing it? Personally I would treat it just like any other Map<K, List> and provide a different convenience method putToValue(K, V) that puts V into the List that is the value for K.

I suppose it depends on your intentions and usage, but strictly speaking I can't fathom ever thinking "I need a class that isn't a Map but impelments Map!" while I can fathom thinking "I need a class that is a Map<K, List> and has a method to make adding something to the list easier!"
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
In fact, it'd be easy to just make it a decorator.

Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[Ken]: Yeah, but that seems like needlessly breaking the Map contract. If you're going to break it, why bother implementing it?

EFH never said he was implementing Map. He uses a Map internally, and he has a put() method which looks similar to the one defined by Map, but that doesn't mean he's implementing Map.

[Ken]: In fact, it'd be easy to just make it a decorator.

Yep - note that the Jakarta Commons version is a decorator. Though they've redefined put(), whereas you've created an additional method putToValue(). I would note that in general I wouldn't want to assume a List for the values, as a Set might well be more appropriate in some applications. So using a Collection seems more approriate to me. Jakarta's version lets you specify a Factory for the value collections, so you can choose the implementation most appropriate.

I'm not sure how much value there is in exposing the other Map methods though. If I'm using a MultiValueMap, I probably don't want to use the traditional Map.put() directly - that's up to the MultiValueMap() to handle. So to me it seems safer to deny the client access to that method, either by redefining it as they do in Jakarta Commons, or my simply not implementing the tradtional Map interface at all, as I belive EFH was advocating. Though having some of the other Map methods might be useful, e.g. keySet(), so maybe it's time for some Commons-like library to provide a more elaborate MultiMap interface and implementation which does not inherit from the traditional Map, and which also uses generics.
[ November 01, 2006: Message edited by: Jim Yingst ]
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Originally posted by Jim Yingst:
[Ken]: Yeah, but that seems like needlessly breaking the Map contract. If you're going to break it, why bother implementing it?

EFH never said he was implementing Map. He uses a Map internally, and he has a put() method which looks similar to the one defined by Map, but that doesn't mean he's implementing Map.


The OP specifically asked for a Map and I misread "has a Map..." as "is a Map...".

Originally posted by Jim Yingst:
[Ken]: In fact, it'd be easy to just make it a decorator.

Yep - note that the Jakarta Commons version is a decorator. Though they've redefined put(), whereas you've created an additional method, which probably makes more sense. I would also note that in general I wouldn't assume a List for the values, as a Set might well be more appropriate in some applications. So using a Collection seems more approriate.


I'm thinking of situations where you want to pass around a Map and there's essentially a Collection of values for each key. It's possible to do that with any Map, but a decorator would greatly simplify doing so. I've had a need for this before and unfortunately ended up creating a class whose sole purpose was to act as a key that could be generated from an enum so that I could associate more than one record with each enum.

As for using a Collection: the problem with that is that if a value doesn't exist we need to create one. If you generified it so that the type of Collection could be specified you'd also need a mechanism for creating the values when they don't exist. It's quite possible of course but it also bloats the API and makes it more complicated to use and you'd have to introduce a third parameterized type.

Originally posted by Jim Yingst:
I'm not sure how much value there is in exposing the other Map methods though. If I'm using a MultiValueMap, I probably don't want to use the traditional Map.put() directly - that's up to the MultiValueMap() to handle. So to me it seems safer to deny the client access to that method, either by redefining it as they do in Jakarta Commons, or my simply not implementing the tradtional Map interface at all, as I belive EFH was advocating. Though having some of the other Map methods might be useful, e.g. keySet(), so maybe it's time for a more elaborate MultiMap interface and implementation which does not inherit from the traditional Map, and which also uses generics.


I don't know either but I don't see much harm in leaving it there. When you want both easy access to the elements in each value and you need to use it as a Map it would certainly help. Plus, it leaves open the possibility of simply grabbing a specific List of elements and passing it off or replacing the entire List of elements without having to grab the List, remove everything, then add everything. It also leaves open the ability to set map certain keys to a specific implementation of List.
[ November 01, 2006: Message edited by: Ken Blair ]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[Ken]: It's quite possible of course but it also bloats the API and makes it more complicated to use and you'd have to introduce a third parameterized type.

Hmmm, seems like most people could just use a default implementation, not knowing or caring about the type of Collection used. Many others could specify the Collection type with a Factory, but still wouldn't really need the specific Collection subtype to come back to them in the API, as most of the time they just need to call iterator(), contains(), add() or remove(). So maybe a third parameterized type can be avoided here. Alternately the library could provide a set of the common Factory options that people might want, so they don't need to spend time fussing with the parameterized types. Maybe by default they'd just use something like

and when they need something more specific, something like

The MultiMap2 is my inelegant way to allow some users to specify a third parameterized type without forcing everyone else to type an extra ", ?" in their declarations. Which wouldn't be the end of the world of course, but it's mildly annoying; I'm looking to avoid it. I couldn't think of a better name for the second interface than MultiMap2; I'm open to suggestions.
[ November 01, 2006: Message edited by: Jim Yingst ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Duplicate keys in Map