Reputation: 699
I've tried to build my own Map to increase the performance for a special environment, and I realized something pretty interesting: Creating a new Hashmap<Integer,String>(2000)
is faster than new Object[2000]
- no matter in which order I execute these commands. That's pretty confusing to me, esp. because the Hashmap constructor contains a table = new Entry[capacity]
, according to this. Is there something wrong with my testbench?
public static void test(int amm){ //amm=1_000_000
Map<Integer,String> m1 = null;
Object[] arr = null;
long time = System.nanoTime();
for(int i = 0; i < amm; i++){
m1 = new HashMap<Integer, String>(2000);
}
System.out.println("m1: " + (System.nanoTime() - time)); //m1: 70_455_065
time = System.nanoTime();
for(int i = 0; i < amm; i++){
arr = new Object[2000];
}
System.out.println("arr: " + (System.nanoTime() - time)); //arr: 1_322_473_803
}
I'd love to see the results of testing on another computer. I've got no clue why creating a HashMap
is 10 times faster than creating a Object[]
.
Upvotes: 44
Views: 3298
Reputation: 34169
If you look at the implementation of HashMap
, the constructor looks like:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
threshold = initialCapacity;
init();
}
And init()
looks like:
/**
* Initialization hook for subclasses. This method is called
* in all constructors and pseudo-constructors (clone, readObject)
* after HashMap has been initialized but before any entries have
* been inserted. (In the absence of this method, readObject would
* require explicit knowledge of subclasses.)
*/
void init() {
}
So initialCapacity
doesn't actually get used to create an array. Where does it get used? Look at the put()
method.
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
// hidden
}
When doing a put, the array is actually created. I didn't show inflateTable()
but it does some math and initializes the array.
Upvotes: 51
Reputation: 993901
An empty HashMap
object is much smaller than an array of 2000 Object
references. Even though you pass 2000 to the initialCapacity
parameter of the HashMap
constructor, it's not actually creating 2000 spaces for objects yet.
Upvotes: 21