5

I have a class with several key-value lists. Each key (within a list) should be unique, so I use HashMap. When somewhere in the code I add a new item to a list, I am using HashMap's put(K, V). I'd like my code to throw an exception if an attempt is made to add an item with already existing key. And, because such adding is performed in many places in the program, I would like to avoid adding checking in each of them. So it should be the list class itself that would not allow replacing existing key-value pair.

I thought of extending the HashMap class with my own one, which would perform such a check and throw an exception. However, HashMap's put does not throw exceptions, so I cannot do it either.

What would be a good approach to achieve such behaviour? I am ready to replace HashMap with something better, but I need it to be fast in both adding and retrieving items.

Update: Thanks all for many nice suggestions. Since I am a complete newbie in Java, I now need to learn a lot to be able to choose the best one :) Anyway, I am grateful for getting so many options within a lunch-break!

texnic
  • 3,959
  • 4
  • 42
  • 75

6 Answers6

8

You can use Commons Collections for this, something like:

Map map = MapUtils.predicatedMap(new HashMap(), PredicateUtils.uniquePredicate(),
             null);

This will create a Map instance that will throw an exception whenever you try inserting a key-value pair when the same key already exists.

Of course, you can customize this behaviour by constructing your own Predicate instance and using it instead of PredicateUtils.uniquePredicate(). Your own Predicate can do whatever you need it to do, so for example, it could throw a different type of exception than the one thrown by the default uniquePredicate().

Isaac
  • 16,458
  • 5
  • 57
  • 81
7

I wouldn't extend HashMap class, since in this case, it would lead to a violation of Liskov Substitution Principle because you alter behavior of a base class method.

Instead I would use composition:

Create your CustomHashMap class implementing Map interface and HAVING an HashMap field. And redeclare every methods present in HashMap class, adding a delegation to the original HashMap for each except for the put() method => throw an exception if entry already exists.

Mik378
  • 21,881
  • 15
  • 82
  • 180
2

Several ideas:
A. Throw an exception that extends RuntimeException in your class that extends HashMap.
B. Provide some sort of MapWrapper that will recieve a Map as parameter, will have get, put, and some other methods , with signatures that suits you more.

Yair Zaslavsky
  • 4,091
  • 4
  • 20
  • 27
1

The javadoc for Map#put states:

throws IllegalArgumentException if some property of the specified key or value prevents it from being stored in this map

I think your use case falls into that category and I would therefore use that possibility. Since it is an unchecked exception, you could use composition, wrap a HashMap and throw an IllegalArgumentException on duplicates in the put method.

assylias
  • 321,522
  • 82
  • 660
  • 783
0

You could throw an Exception that extens RuntimeException.

AlexWien
  • 28,470
  • 6
  • 53
  • 83
  • 2
    Hey you downvoter, my answer is valid. Give reason why you downvote – AlexWien Nov 23 '12 at 10:53
  • 1
    I wasn't the downvoter, but I believe that the reason for downvoting was that you proposed a solution that would require the OP to explicitly code the duplicity check themselves, whereas the OP clearly states that they're looking for a mechanism that will do it automagically. – Isaac Nov 23 '12 at 10:59
  • 1
    @AlexWien I didn't downvote but you would violate Liskov Substitution Principle. – Mik378 Nov 23 '12 at 11:00
  • @Mik No not realy, if he does not derive, but uses composition whch in most cases is the favorable technic, then he still cam implement the map interface, and throwing an runtime exception. – AlexWien Nov 23 '12 at 11:02
  • @isaac the OP statet that he dont wantbto check for dupps outside the class. But will do inside – AlexWien Nov 23 '12 at 11:06
  • @AlexWien, your answer was "You could throw an Exception that extens RuntimeException." How does that answer the OP's question? – Isaac Nov 23 '12 at 11:07
  • @Isaac in the `put` method of the subclass of `HashMap`: `if (map.contains(newKey)) throw new RuntimeException();` – assylias Nov 23 '12 at 11:08
  • Yes the OP should have understood, but to be clean, not directoy the Runtime Exception, better an own one, or the IllegalArgumentException – AlexWien Nov 23 '12 at 11:09
  • Look, I'm not saying that composition doesn't work. All I'm saying is that the answer's text - "You could throw an Exception that extens RuntimeException." - doesn't answer the OP's question. The explanations in the comments explain it better, yes; but Alex was asking why the downvote... so those were my $0.02. (I wasn't the downvoter) – Isaac Nov 23 '12 at 11:11
  • It was a fast answer, which allows the OP who has understood, to progress his work fast. – AlexWien Nov 23 '12 at 11:25
0

You can extend HashMap and throw an Exception that is subclass of RuntimeException or one of the Exception already thrown by the put method.

pringi
  • 3,987
  • 5
  • 35
  • 45