谷歌提供了guava包里面有很多的工具类,现在来看Maps这个集合工具,对map集合操作做了些优化提升。
现提供如下使用实例。
package com.lxk.guavaTest;
import com.google.common.collect.Maps;
import java.util.Iterator;
import java.util.Map;
/**
* guava Maps 测试实例
* <p>
* Created by lxk on 2016/11/14
*/
public class MapsTest {
public static void main(String[] args) {
testMaps();
}
/**
* 测试 guava Maps
*/
private static void testMaps() {
Map<Integer, Integer> map0 = Maps.newHashMap();
for (int i = 0; i < 10; i++) {
map0.put(i, i);
}
System.out.println("map0:" + map0);
Map<Integer, Integer> map1 = Maps.newHashMap(map0);
map1.put(10, 10);
System.out.println("map1:" + map1);
//下面的这个写法呢是在初始化list的时候,说明容器的扩容界限值
//使用条件:你确定你的容器会装多少个,不确定就用一般形式的
//说明:这个容器超过3个还是会自动扩容的。不用担心容量不够用。默认是分配一个容量为16的数组,不够将扩容
//详细见后面说明
Map<Integer, Integer> map2 = Maps.newHashMapWithExpectedSize(3);
Map<String,String> map9 = Maps.newHashMapWithExpectedSize();
map2.put(1, 1);
map2.put(2, 2);
map2.put(3, 3);
System.out.println("map2:" + map2);
//LinkedHashMap<K, V> 有序map
//Map<Integer,Integer> map3 = Maps.newLinkedHashMap();
Map<Integer, Integer> map3 = Maps.newLinkedHashMap(map1);
//Map<Integer,Integer> map3 = Maps.newLinkedHashMapWithExpectedSize(11);
map3.put(11, 11);
System.out.println("map3:" + map3);
outMapKeyValue(map3);
}
/**
* 遍历Map的四种方法
*/
private static void outMapKeyValue(Map<Integer, Integer> map3) {
//1.通过Map.entrySet遍历key和value
for (Map.Entry<Integer, Integer> integerEntry : map3.entrySet()) {
System.out.println("key:" + integerEntry.getKey() + " value:" + integerEntry.getValue());
}
//2.通过Map.entrySet使用iterator遍历key和value-----不推荐,直接用上面的for each循环代替此方法
Iterator<Map.Entry<Integer, Integer>> it = map3.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> entry = it.next();
System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
}
//3.通过Map.keySet遍历key;根据key得到value
for (Integer integer : map3.keySet()) {
System.out.println("key:" + integer + " value:" + map3.get(integer));
}
//4.通过Map.values()遍历所有的value,但不能遍历key
for (Integer integer : map3.values()) {
System.out.println("value:" + integer);
}
}
}
下面先是关于Maps.newHashMapWithExpectedSize(3)的源码简单分析
//返回一个 新的、空的hashmap实例,有足够多(expectedSize个)的节点(entries),保证添加过程不出现resize
//@return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries without resizing
public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
return new HashMap<K, V>(capacity(expectedSize));
}
static int capacity(int expectedSize) {
if (expectedSize < 3) {
checkNonnegative(expectedSize, "expectedSize");
return expectedSize + 1;
}
if (expectedSize < Ints.MAX_POWER_OF_TWO) { //MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
// This is the calculation used in JDK8 to resize when a putAll
// happens; it seems to be the most conservative(保守的) calculation we
// can make. 0.75 is the default load factor.
return (int) ((float) expectedSize / 0.75F + 1.0F);
}
return Integer.MAX_VALUE; // any large value //MAX_VALUE = 0x7fffffff;
}
static int checkNonnegative(int value, String name) {
if (value < 0) {
throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
}
return value;
}
//以下就是hashmap源码部分了。
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);//DEFAULT_LOAD_FACTOR = 0.75f;加载因子默认是0.75f
}
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;//hash table 加载因子
threshold = initialCapacity;//
init();
}
//threshold属性:英文翻译为:阈值。注释如下,就是hashmap resize的临界值。
/**
* The next size value at which to resize (capacity * load factor).
* @serial
*/
// If table == EMPTY_TABLE then this is the initial capacity at which the
// table will be created when inflated.
int threshold;
hashmap底层实现是如下的一个对象数组。
/**
* An empty table instance to share when the table is not inflated.
*/
static final Entry<?,?>[] EMPTY_TABLE = {};
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
Maps.newHashMapWithExpectedSize(3),初始化一个大小合适的map集合,避免在向集合添加元素的时候,因为大小不
合适而resize,每次resize都得执行以下步骤:再次去分配空间,再次去计算所以元素的hashcode,再次根据hashcode
计算数组的分配位置,然后数组拷贝。这样就可以大大提升 在使用hashmap时候的性能。和不必要的空间浪费。
resize默认是*2来扩容的。
resize(2 * table.length);