Java efficient counters

Source: Internet
Author: User

We often use HashMap as a counter to count something in a database or text. In this article, we will use HashMap to compare the three different counter methods. 1. if a beginner-level counter uses this type of counter, the code is roughly as follows: [java] String source = "my name is name me and your name is her first her "; string [] words = source. split (""); // newbie-level counter public static void testNaive (String [] words) {HashMap <String, Integer> counter = new HashMap <String, Integer> (); for (String w: words) {if (counter. containsKey (w) {int oldValue = counter. get (w); counter. put (w, oldValue + 1);} else {counter. put (W, 1) ;}} in each cycle, determine whether the corresponding key is included. If so, add 1 to the original value. If not, set it to 1. this method is simple and direct, but not very efficient. 1.1 when a key exists, containsKey () and get () are called once, which means that map is searched twice. 1.2 because Integer is unchangeable, a new object will be created when the Count value is added in each loop. 2. for entry-level counters, we naturally need a variable Integer to avoid creating too many Integer objects. variable Integer classes can be defined as follows: [java] // variable Integer public static final class MutableInteger {private int val; public MutableInteger (int val) {this. val = val;} public int get () {return this. val;} public void set (int val) {this. val = val;} // print public String toString () {return Integer for convenience. toString (val) ;}} then the counter can be used as follows Improvement: [java] // entry level counter public static void testBetter (String [] words) {HashMap <String, MutableInteger> counter = new HashMap <String, MutableInteger> (); for (String w: words) {if (counter. containsKey (w) {MutableInteger oldValue = counter. get (w); oldValue. set (oldValue. get () + 1); // because it is referenced, A HashMap query is reduced.} else {counter. put (w, new MutableInteger (1) ;}} it looks better because there is no need to create too many Integer objects. However, if the key exists, you still need to perform two searches each cycle. 3. the put (key, value) method of the HashMap of the superior counter returns the current value corresponding to the key. to learn about this feature, we can use the original value to increment without multiple searches. [java] public static void testEfficient (String [] words) {HashMap <String, MutableInteger> counter = new HashMap <String, MutableInteger> (); for (String w: words) {MutableInteger initValue = new MutableInteger (1); // use the HashMap put Method to pop up the MutableInteger oldValue = counter. put (w, initVa Lue); if (oldValue! = Null) {initValue. set (oldValue. get () + 1) ;}}4. The following code is used to test the performance of the three methods. First, let's take a look at the results. The performance tests were executed multiple times. For each order of magnitude test, the error is not too large. So one of the results is arranged as follows: [plain] 10000000 cycles: beginner level counter: 7726594902 entry level counter: 6516014840 excellent level counter: 5736574103 1000000 cycle: beginner level counter: 777480106 entry level counter: 642932000 excellent level counter: 571867738 100000 cycle: beginner level counter: 84323682 entry level counters: 70176906 excellent level counters: 61219664 10000 cycles: beginner level counters: 13279550 entry level counters: 7874100 excellent level counters: 6460172 1000 cycles: beginner level counters: 4542172 entry level counters: 2933248 excellent counters: 992749 100 cycles: Beginner counters: 30923 25 Entry level counters: 1101695 excellent level counters: 423942 10 cycles: beginner level counters: 1993788 entry level counters: 558150 excellent level counters: 153156 1 cycle: beginner level counters: 1625898 entry level counters: 427494 excellent counters: 69473 from the above output, we can see that 10000 times, at, the difference is very obvious. in particular, the ratio between beginner-level counters and entry-level counters indicates that creating an object is a resource-consuming operation. Of course, the less obvious difference in the number of times is that it triggers multiple GC garbage collection times and proves that the cost of garbage collection is indeed high. The complete test code is as follows: [java] import java. util. hashMap; public class TestCounter {public static void main (String [] args) {// source String source = "my name is name me and your name is her first her "; // timing, unit: microsecond long startTime = 0; long endTime = 0; long duration = 0; // number of tests int loop = 1*10000; System. out. println (loop + "loop:"); startTime = System. nanoTime (); testNaive (source, loop); endTime = System. nanoT Ime (); duration = endTime-startTime; System. out. println ("novice counters:" + duration); // startTime = System. nanoTime (); testBetter (source, loop); endTime = System. nanoTime (); duration = endTime-startTime; System. out. println ("entry level counter:" + duration); // startTime = System. nanoTime (); testEfficient (source, loop); endTime = System. nanoTime (); duration = endTime-startTime; System. out. println ("premium counters :" + Duration);} // newbie-level counter public static void testNaive (String source, int loop) {if (null = source) {return ;} // String [] words = source. split (""); for (int I = 0; I <loop; I ++) {testNaive (words) ;}} public static void testNaive (String [] words) {HashMap <String, Integer> counter = new HashMap <String, Integer> (); for (String w: words) {if (counter. containsKey (w) {int oldValue = counter. get (w ); Counter. put (w, oldValue + 1);} else {counter. put (w, 1) ;}}// variable Integer public static final class MutableInteger {private int val; public MutableInteger (int val) {this. val = val;} public int get () {return this. val;} public void set (int val) {this. val = val;} // print public String toString () {return Integer for convenience. toString (val) ;}// entry level counter public static void testBetter (String source, int loop) {If (null = source) {return;} // String [] words = source. split (""); for (int I = 0; I <loop; I ++) {testBetter (words) ;}} public static void testBetter (String [] words) {HashMap <String, MutableInteger> counter = new HashMap <String, MutableInteger> (); for (String w: words) {if (counter. containsKey (w) {MutableInteger oldValue = counter. get (w); oldValue. set (oldValue. get () + 1); // because it is a reference, H is reduced. AshMap lookup} else {counter. put (w, new MutableInteger (1) ;}}// counter of excellence level public static void testEfficient (String source, int loop) {if (null = source) {return;} // String [] words = source. split (""); for (int I = 0; I <loop; I ++) {testEfficient (words) ;}} public static void testEfficient (String [] words) {HashMap <String, MutableInteger> counter = new HashMap <String, MutableInteger> (); for (Stri Ng w: words) {MutableInteger initValue = new MutableInteger (1); // use the put Method of HashMap to bring up the feature of the old value MutableInteger oldValue = counter. put (w, initValue); if (oldValue! = Null) {initValue. set (oldValue. get () + 1) ;}}} when you use the counter, you may also need to sort it by value. For details, refer to: the frequently used method of HashMap. 5. I think the best comment on the Keith website comment list is as follows: I added three tests: 1) restructured the "entry level counter", instead of using the containsKey, instead I only use the get method. generally, the elements you need exist in HashMap, so you can streamline the two searches to one. 2) the method mentioned by the author michal is implemented using AtomicInteger. 3) using a single int array for comparison, you can use less memory, see http://amzn.com/0748614079 I ran the test program three times, and pick out the smallest value (to reduce interference ). note: you cannot cause too much interference to the running results in the program, because the memory Insufficient may be affected by too many gc recyclers. beginner counters: 201716122 entry-level counters: 112259166 excellent counters: 93066471 entry-level counters (do not use containsKey): 69578496 entry-level counters (do not use containsKey, with AtomicInteger ): 94313287 entry-level counters (do not use containsKey, with int []): 65877234 entry-level counters (do not use the containsKey method :): [java] HashMap <string, mutableinteger = ""> efficientCounter2 = new HashMap <string, mutableinteger = ""> (); for (int I = 0; I <NUM_ITERATIONS; I ++) for (String: sArr) {MutableInteger value = efficientCounter2.get (a); if (value! = Null) {value. set (value. get () + 1);} else {efficientCounter2.put (a, new MutableInteger (1);} entry-level counter (containsKey is not used, AtomicInteger is used ): [java] HashMap <string, atomicinteger = ""> atomicCounter = new HashMap <string, atomicinteger = ""> (); for (int I = 0; I <NUM_ITERATIONS; I ++) for (String a: sArr) {AtomicInteger value = atomicCounter. get (a); if (value! = Null) {value. incrementAndGet ();} else {atomicCounter. put (a, new AtomicInteger (1) ;}} entry-level counter (containsKey is not used, int []): [java] HashMap <string, int [] = ""> intCounter = new HashMap <string, int [] = ""> (); for (int I = 0; I <NUM_ITERATIONS; I ++) for (String a: sArr) {int [] valueWrapper = intCounter. get (a); if (valueWrapper = null) {intCounter. put (a, new int [] {1});} The MultiSet of else {valueWrapper [0] ++ ;}} Guava language may be faster. 6. conclusion The winner uses an int array.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.