Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HashMap - contains and get methods should not be used together

I got the following question from an interview.

I was given a character array like this:

char[] characters = {'u', 'a', 'u', 'i', 'o', 'f', 'u'}; 

I needed to get the distinct characters and counts of each character:

u = 3 a = 1 i = 1 o = 1 f = 1 

So I answered in Java with the following code:

HashMap<Character, Integer> map = new HashMap<Character, Integer>(); int i = 1; for (char c : characters) {                  if (map.containsKey(c)) {         int val = map.get(c);         map.put(c, ++val);     } else map.put(c, i); } 

The interviewer was a solution architect. He asked me why I was using both containsKey() and get() methods here and noted that it was redundant to use both methods. What is his point? What was I doing wrong here? Will my code cause a performance issue, etc.?

like image 395
E Do Avatar asked May 29 '15 05:05

E Do


People also ask

What is the problem with HashMap?

Yes, it will cause major problems. One example is what could happen when adding a value to the hash map: this can cause a rehash of the table, and if that occurs while another thread is iterating over a collision list (a hash table "bucket"), that thread could erroneously fail to find a key that exists in the map.

Can I use Contains with HashMap?

HashMap. containsKey() method is used to check whether a particular key is being mapped into the HashMap or not. It takes the key element as a parameter and returns True if that element is mapped in the map.

What is the significant difference between containsKey () and get ()?

get(Object) does explicitly warn about the subtle differences between Map. get(Object) and Map. containsKey(Object) : If this map permits null values, then a return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null .

What does get method do in HashMap?

get() method of HashMap class is used to retrieve or fetch the value mapped by a particular key mentioned in the parameter. It returns NULL when the map contains no such mapping for the key.


2 Answers

The architect means that get and containsKey have the same costs and may be accumulated into one check:

Integer val = map.get(c); if (val != null) {   ... } else {   ... } 

But I wonder why the architect is only concerned about that, as there are more things to improve:

  • Refer to objects by their interfaces (Effective Java 2nd Edition, Item 52)
  • Since Java 1.7 you can use the diamond operator <>
  • Accumulate the autoboxing operations of the characters
  • If you use AtomicInteger (or any other modifiable number class) instead of Integer you can even merge the get with one of the puts

So from my point of view the best performance, when using a HashMap, would offer:

Map<Character, AtomicInteger> map = new HashMap<>(); for (Character c : characters) {     AtomicInteger val = map.get(c);     if (val != null) {         val.incrementAndGet();     } else {         map.put(c, new AtomicInteger(1));     } } 

If the range of your characters is small (and known in advance), you could use an int array for counting. This would be the fastest of all possible solutions:

char firstCharacter = 'a'; char lastCharacter = 'z'; int[] frequency = new int[lastCharacter - firstCharacter + 1]; for (char c : characters) {   frequency[c - firstCharacter]++; } 
like image 87
Tobias Liefke Avatar answered Sep 20 '22 01:09

Tobias Liefke


Your code is redundant, since both get and containsKey do pretty much the same work. Instead of calling containsKey you can check whether get returns a null value.

The code can be reduced to :

HashMap<Character, Integer> map = new HashMap<Character, Integer>(); for (char c : characters) {        Integer val = map.get(c);               if (val == null)         val = 0;     map.put(c,++val); } 
like image 23
Eran Avatar answered Sep 17 '22 01:09

Eran