Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quickest implementation of Java Map for a small number of entries

What is the quickest implementation of java.util.Map for a very small number of entries (under 15 elements or so)? Both thread-safe and non-thread-safe.

like image 543
patstuart Avatar asked Jul 28 '14 18:07

patstuart


People also ask

Which is the fastest Map in Java?

HashMap will generally be fastest, since it has the best cache behavior ( HashMap iterates directly over the backing array, whereas TreeMap and LinkedHashMap iterate over linked data structures).

Which Java Map implementation offers the best performance?

HashMap, being a hashtable-based implementation, internally uses an array-based data structure to organize its elements according to the hash function. HashMap provides expected constant-time performance O(1) for most operations like add(), remove() and contains(). Therefore, it's significantly faster than a TreeMap.

Which is faster TreeMap or HashMap?

Conclusions. HashMap is a general purpose Map implementation. It provides a performance of O(1) , while TreeMap provides a performance of O(log(n)) to add, search, and remove items. Hence, HashMap is usually faster.

Is HashMap faster than ArrayList?

The ArrayList has O(n) performance for every search, so for n searches its performance is O(n^2). The HashMap has O(1) performance for every search (on average), so for n searches its performance will be O(n). While the HashMap will be slower at first and take more memory, it will be faster for large values of n.


1 Answers

If all entries can be represented as Enums, use EnumMap:

This implementation combines the richness and safety of the Map interface with a speed approaching that of an array. If you want to map an enum to a value, you should always use an EnumMap in preference to an array.

If no, HashMap is good solution. It provides constant time for basic operations, like get() and put():

This implementation provides constant-time performance for the basic operations (get and put), assuming the hash function disperses the elements properly among the buckets.

Just rembember to set low capacity value in your HashMap:

Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.

Of course, above implementations are not thread safe. The best thread-safe implementation in this case will be ConcurrentHashMap. It combines high performance of HashMap with being thread-safe.

Here is good comparison of different Map implementations.

Edit: Here is an interesting comparison of different HashMap implementations. It seems, that, at least for primitive types, there are faster alternatives than built-in HashMap.

Edit2: Due to Peter Lawrey's answer I decided to perform some test, comparing ConcurrentHashMap and Collections.synchronizedMap() :

public static void main(String[] args) {
      System.out.println("\n===== ConcurrentHashMap =====");
      testMap(new ConcurrentHashMap<>());
      System.out.println("\n===== Collections.synchronizedMap()  =====");
      testMap(Collections.synchronizedMap(new HashMap<>()));
}

    static final int N = 5;
    static final int R = 1000000;

    public static void testMap(Map map) {
        long startTime = System.nanoTime();

        System.out.println("\n-- " + N*R + " puts(key, value) --");
        startTime = System.nanoTime();
        for (int j = 0; j < R; j++) {
            for (int i = 0; i < N; i++) 
                map.put(i, new float[] { 0f, 1f, 2f, 3f, 4f });
            map.clear();
        }
        System.out.println((System.nanoTime() - startTime) / 1000000000.0);

        System.out.println("\n-- " + N*R + " get(key) --");
        startTime = System.nanoTime();
        for (int j = 0; j < R; j++) {
            for (int i = 0; i < N; i++)  
                map.get(i); 
            map.clear();
        }
        System.out.println((System.nanoTime() - startTime) / 1000000000.0);
    }

}

My results are:

===== ConcurrentHashMap =====

  • 5000000 puts(key, value) - 0.99714195 s

  • 5000000 get(key) - 0.452227427 s

===== Collections.synchronizedMap() =====

  • 5000000 puts(key, value) - 0.586431367 s

  • 5000000 get(key) - 0.376051088 s

So, Peter is probably right - for small maps, Collections.synchronizedMap() is faster.

like image 124
Kao Avatar answered Oct 05 '22 00:10

Kao