How to increment a Map value in Java

Your ads will be inserted here by

Easy Plugin for AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

Reference to http://stackoverflow.com/questions/81346/most-efficient-way-to-increment-a-map-value-in-java

The guy from stackoverflow has tested several methods:

  • the “ContainsKey” method that I presented in the question
  • the “TestForNull” method suggested by Aleksandar Dimitrov
  • the “AtomicLong” method suggested by Hank Gay
  • the “Trove” method suggested by jrudolph
  • the “MutableInt” method suggested by phax.myopenid.com

Method

Here’s what I did…

  1. created five classes that were identical except for the differences shown below. Each class had to perform an operation typical of the scenario I presented: opening a 10MB file and reading it in, then performing a frequency count of all the word tokens in the file. Since this took an average of only 3 seconds, I had it perform the frequency count (not the I/O) 10 times.
  2. timed the loop of 10 iterations but not the I/O operation and recorded the total time taken (in clock seconds) essentially using Ian Darwin’s method in the Java Cookbook.
  3. performed all five tests in series, and then did this another three times.
  4. averaged the four results for each method.

Results

I’ll present the results first and the code below for those who are interested.

The ContainsKey method was, as expected, the slowest, so I’ll give the speed of each method in comparison to the speed of that method.

  • ContainsKey: 30.654 seconds (baseline)
  • AtomicLong: 29.780 seconds (1.03 times as fast)
  • TestForNull: 28.804 seconds (1.06 times as fast)
  • Trove: 26.313 seconds (1.16 times as fast)
  • MutableInt: 25.747 seconds (1.19 times as fast)

Conclusions

It would appear that only the MutableInt method and the Trove method are significantly faster, in that only they give a performance boost of more than 10%. However, if threading is an issue, AtomicLong might be more attractive than the others (I’m not really sure). I also ran TestForNull with final variables, but the difference was negligible.

Note that I haven’t profiled memory usage in the different scenarios. I’d be happy to hear from anybody who has good insights into how the MutableInt and Trove methods would be likely to affect memory usage.

Your ads will be inserted here by

Easy Plugin for AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

Personally, I find the MutableInt method the most attractive, since it doesn’t require loading any third-party classes. So unless I discover problems with it, that’s the way I’m most likely to go.

The code

Here is the crucial code from each method.

ContainsKey

<code>import java.util.HashMap; import java.util.Map; ... Map&lt;String, Integer&gt; freq = new HashMap&lt;String, Integer&gt;(); ... int count = freq.containsKey(word) ? freq.get(word) : 0; freq.put(word, count + 1);</code>

TestForNull

<code>import java.util.HashMap; import java.util.Map; ... Map&lt;String, Integer&gt; freq = new HashMap&lt;String, Integer&gt;(); ... Integer count = freq.get(word); if (count == null) { freq.put(word, 1); } else { freq.put(word, count + 1); }</code>

AtomicLong

<code>import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; ... final ConcurrentMap&lt;String, AtomicLong&gt; map = new ConcurrentHashMap&lt;String, AtomicLong&gt;(); ... map.putIfAbsent(word, new AtomicLong(0)); map.get(word).incrementAndGet();</code>

Trove

<code>import gnu.trove.TObjectIntHashMap; ... TObjectIntHashMap&lt;String&gt; freq = new TObjectIntHashMap&lt;String&gt;(); ... freq.adjustOrPutValue(word, 1, 1);</code>

MutableInt

<code>import java.util.HashMap; import java.util.Map; ... class MutableInt { int value = 1; // note that we start at 1 since we're counting public void increment () { ++value; } public int get () { return value; } } ... Map&lt;String, MutableInt&gt; freq = new HashMap&lt;String, MutableInt&gt;(); ... MutableInt count = freq.get(word); if (count == null) { freq.put(word, new MutableInt()); } else { count.increment(); }</code>

Read More