Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Agile forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Duplicate keys in Map

 
Ayan Dutta
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 10336
Eclipse IDE Hibernate Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why do this? Would you not be better using some sort of Value Object/DTO and a List? What are you trying to achieve?
 
Ayan Dutta
Ranch Hand
Posts: 94
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just for a test , I want To do this .To see whether it can be done or not .
Regards ,
Ayan
 
Paul Sturrock
Bartender
Posts: 10336
Eclipse IDE Hibernate Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 208
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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 ]
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In fact, it'd be easy to just make it a decorator.

 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[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
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[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 ]
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic