How to set initial size for HashMap
1. Requirements of Alibaba code specifications
2. When scanning using Alibaba plug-in
3. Source code
3.1 When initialization does not set the size
Map<Integer, BigDecimal> staffDidiMap = new HashMap<>();
3.2 When initializing the size
Map<Integer, BigDecimal> staffDidiMap = new HashMap<>(16);
@Test
public void caffineTest() {
System.out.println(1 << 30);
}
result: 1073741824
this.threshold = tableSizeFor(initialCapacity);
@Test
public void caffineTest() {
int cap = 16;
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
int result = (n < 0) ? 1 : (n >= 1073741824) ? 1073741824 : n + 1;
System.out.println(result);
}
result: 16
//TODO source code part needs to be improved
4. Test
@SpringBootTest
public class CaffineTest {
@Test
public void caffineTest() throws InterruptedException {
test1();
test2();
test3();
test4();
test5();
}
void test1() throws InterruptedException {
int aHundredMillion = 10000000;
Map<Integer, Integer> map = new HashMap<>();
long s1 = System.currentTimeMillis();
for (int i = 0; i < aHundredMillion; i++) {
map.put(i, i);
}
long s2 = System.currentTimeMillis();
System.out.println("未初始化容量,耗时 : " + (s2 - s1));
map.clear();
Thread.sleep(5000);
}
void test2() throws InterruptedException {
int aHundredMillion = 10000000;
Map<Integer, Integer> map1 = new HashMap<>(aHundredMillion / 2);
long s5 = System.currentTimeMillis();
for (int i = 0; i < aHundredMillion; i++) {
map1.put(i, i);
}
long s6 = System.currentTimeMillis();
System.out.println("初始化容量5000000,耗时 : " + (s6 - s5));
map1.clear();
Thread.sleep(5000);
}
void test3() throws InterruptedException {
int aHundredMillion = 10000000;
Map<Integer, Integer> map2 = new HashMap<>(aHundredMillion);
long s3 = System.currentTimeMillis();
for (int i = 0; i < aHundredMillion; i++) {
map2.put(i, i);
}
long s4 = System.currentTimeMillis();
System.out.println("初始化容量为10000000,耗时 : " + (s4 - s3));
map2.clear();
Thread.sleep(5000);
}
void test4() throws InterruptedException {
int aHundredMillion = 10000000;
// 按照阿里巴巴规范 initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认 为 0.75
int initial = (int) (aHundredMillion / 0.75F + 1F);
Map<Integer, Integer> map3 = new HashMap<>(initial);
long s7 = System.currentTimeMillis();
for (int i = 0; i < aHundredMillion; i++) {
map3.put(i, i);
}
long s8 = System.currentTimeMillis();
System.out.println("初始化容量为" + initial + "耗时" + (s8 - s7));
map3.clear();
Thread.sleep(5000);
}
void test5() throws InterruptedException {
int aHundredMillion = 10000000;
// 初始化16
Map<Integer, Integer> map4 = new HashMap<>(16);
long s9 = System.currentTimeMillis();
for (int i = 0; i < aHundredMillion; i++) {
map4.put(i, i);
}
long s10 = System.currentTimeMillis();
System.out.println("初始化容量为" + 16 + "耗时" + (s10 - s9));
map4.clear();
Thread.sleep(5000);
}
}
Result:
Ten million pieces of data are inserted into the map each time.
Method 1: Not initialized,
time consuming 3995. Method 2: Initialization to 5 million,
time consuming 2345. Method 3: Initialization to 10 million
, time consuming 261. Method 4: Initialization according to Alibaba specifications, time consuming 192.
Method 5: Initialization 16, time consuming 182.
! ! !
After many tests, it can be concluded that the worst performance is uninitialized, the most efficient and stable one is according to Alibaba specifications initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认 为 0.75
, then 16 and finally according to the size of the assigned size.
appendix
1. Why does Alibaba recommend that the capacity of HashMap needs to be specified when initializing it?