Java和guava关于hashmap在初始化的时候最好给个初始容量

 

Java和guava关于hashmap在初始化的时候最好给个初始容量,避免扩容引起性能问题的探究。

标签: hashmap初始化设定大小的误区
  207人阅读  评论(0)  收藏  举报
  分类:
java 提高篇(22) 

一般Java的集合初始化如下带初始容量的map:
Map map = new HashMap(4);
本意是希望给HashMap设置初始值, 避免扩容(resize)的开销. 但是没有考虑当添加的元素数量达到HashMap容量的75%时将出现resize.
所以说上面的是徒劳的。错误的。
guava里面有工具类Maps,可以很方便的创建一个集合,并且,带上合适的大小初始化值。具体如下:
Map map = Maps.newHashMapWithExpectedSize(7);


二者的详细对比如下:

[java]  view plain  copy
 
  1. //实际上map的分配大小是根据 7/(0.75) + 1 = 10 去分配大小的;  
  2. //则当元素添加到7个;所以不会触发resize();  
  3. Map map = Maps.newHashMapWithExpectedSize(7);  
  4.   
  5.   
  6.  public static  HashMap newHashMapWithExpectedSize(int expectedSize) {  
  7.    return new HashMap(capacity(expectedSize));  
  8.  }  
  9.   
  10.  static int capacity(int expectedSize) {//expectedSize = 7;这传进去个7,返回的是10;  
  11.    if (expectedSize < 3) {  
  12.      checkNonnegative(expectedSize, "expectedSize");  
  13.      return expectedSize + 1;  
  14.    }  
  15.    if (expectedSize < Ints.MAX_POWER_OF_TWO) {   //MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2); //Integer.SIZE = 32;  
  16.      // This is the calculation used in JDK8 to resize when a putAll  
  17.      // happens; it seems to be the most conservative calculation we  
  18.      // can make.  0.75 is the default load factor.  
  19.      return (int) ((float) expectedSize / 0.75F + 1.0F);  
  20.    }  
  21.    return Integer.MAX_VALUE; // any large value //MAX_VALUE = 0x7fffffff;  int类型的最大值啦;二进制 就是31个1的数字。  
  22.  }  
  23.   
  24.    public HashMap(int initialCapacity) {//这传入的initialCapacity = 10;  
  25.        this(initialCapacity, DEFAULT_LOAD_FACTOR); //static final float DEFAULT_LOAD_FACTOR = 0.75f;  
  26.    }  
  27.   
  28. //Java 1.7是如下算法:结果算出来是capacity = 16;  
  29.        int capacity = 1;  
  30.        while (capacity < initialCapacity)//initialCapacity = 10 传进来的  
  31.            capacity <<= 1;  
  32.           
  33.     threshold = (int) (capacity * loadFactor);//loadFactor = 0.75 默认的,这个扩容极限值是16 * 0.75 = 12即threshold = 12;  
  34. //什么时候resize  
  35. //在添加一个元素即addEntry()的时候有如下判断  
  36.         if (size++ >= threshold)  
  37.            resize(2 * table.length);  
  38.       
  39. //Java 1.8是如下算法:结果算出来是16;额,我是debug看到的是16,下面的移来移去的,看不懂。  
  40. this.threshold = tableSizeFor(initialCapacity);//initialCapacity = 10;穿进去是10,返回的是16;  
  41.   
  42. static final int tableSizeFor(int cap) {  
  43.        int n = cap - 1;  
  44.        n |= n >>> 1;  
  45.        n |= n >>> 2;  
  46.        n |= n >>> 4;  
  47.        n |= n >>> 8;  
  48.        n |= n >>> 16;  
  49.        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;  
  50.    }  
  51. //什么时候resize  
  52. //在添加一个元素即putVal()的时候有如下判断  
  53.        if (++size > threshold)// 我debug的时候,看到这个threshold变成12啦,不知道什么时候,16变12啦;  
  54.            resize();  
  55.   
  56. //为什么呢,不是应该在resize方法里面重置大小之后再修改这个阈值的吗。具体的不知道哪里被修改啦,还是说我的debug的不对。等空了在说吧。 

你可能感兴趣的:(Java和guava关于hashmap在初始化的时候最好给个初始容量)