一、概述
- Map是一种数据结构,以键值对的方式存储数据,每个键都是唯一的,且对应一个值,一种存放键值对的集合。
- java.util.Map,是一个顶级接口,提供了三个集合视图:所有key的集合、所有value的集合、所有key-value的集合。PS:任何对集合视图的修改都会影响原集合。
- Map与Set集合紧密相关,HashSet内部就维护了一个HashMap,实际上HashSet的新增,就是新增了一个key为值,value为默认对象的HashMap元素。
简单介绍一下Set结构特性:
1)无序性:集合中的每个元素都是无序的(java提供SortedSet有序Set)
2)互异性:集合中任意两个元素互异
3)确定性:元素存在与否是确定的
二、源码环境
JDK8
三、源码
先介绍java.util.Map接口,jdk8新增了默认方法。
public interface Map<K,V> { // 查询Operations 返回键值对的个数,如果元素个数大于Integer.MAX_VALUE,返回Integer.MAX_VALUE int size(); 如果Map没有包含元素,返回true;否则返回,false boolean isEmpty(); 是否包含指定key,包含返回true;否则返回,false boolean containsKey(Object key); 是否包含指定value,包含返回true;否则返回,false boolean containsValue(Object value); 根据指定的key,返回对应的value;如果不包含key,返回null V get(Object key); // 修改Operations 新增键值对,如果Map中包含key,返回旧的value;否则返回null V put(K key, V value); 删除集合中指定key,如果map不包含指定key,返回null V remove(Object key); // 批量Operations 将指定map新增至当前map void putAll(Map<? extends K, ? extends V> m); 清除当前map所有元素 void clear(); // 集合视图 返回所有key的set集合 Set<K> keySet(); 返回所有value的集合 Collection<V> values(); 返回所有的键值对的集合 Set<Map.Entry<K, V>> entrySet(); 内部键值对接口 interface Entry<K,V> { 返回key K getKey(); 返回value V getValue(); 设置新value,返回旧的值 V setValue(V value); 判断指定entry和当前entry是否相等 boolean equals(Object o); 返回key的hashCode和value的hashCode的按位异或结果 int hashCode(); jdk8默认方法,返回key值比较器 public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() { return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> c1.getKey().compareTo(c2.getKey()); } jdk8默认方法,返回Value值比较器 public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() { return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> c1.getValue().compareTo(c2.getValue()); } jdk8默认方法,通过指定的key值比较器返回比较器 public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) { Objects.requireNonNull(cmp); return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); } jdk8默认方法,通过指定的value值比较器返回比较器 public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) { Objects.requireNonNull(cmp); return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); } } // 比较和hash 指定map和当前map是否相等 boolean equals(Object o); 返回当前map的hash值 int hashCode(); // 默认方法 JDK8默认方法,获取key查找value,如果key不存在或者value为null返回指定的默认值 default V getOrDefault(Object key, V defaultValue) { V v; return (((v = get(key)) != null) || containsKey(key)) ? v : defaultValue; } jdk8默认方法,用于Lambda表达式,遍历map,通过action处理 default void forEach(BiConsumer<? super K, ? super V> action) { Objects.requireNonNull(action); for (Map.Entry<K, V> entry : entrySet()) { K k; V v; try { k = entry.getKey(); v = entry.getValue(); } catch(IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } action.accept(k, v); } } JDK8默认方法,用于Lambda表达式,提供BiFunction用来根据旧的k-v键值对,生成新的value,并更新当前map default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); for (Map.Entry<K, V> entry : entrySet()) { K k; V v; try { k = entry.getKey(); v = entry.getValue(); } catch(IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } // ise thrown from function is not a cme. v = function.apply(k, v); try { entry.setValue(v); } catch(IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } } } JDK8默认方法,新增键值对,如果当前key已存在且value不为null,返回对应的value;否则新增key-value,返回null default V putIfAbsent(K key, V value) { V v = get(key); if (v == null) { v = put(key, value); } return v; } JDK8默认方法,指定key对应的value和指定的value相等,才会删除key,返回true;否则,返回false default boolean remove(Object key, Object value) { Object curValue = get(key); if (!Objects.equals(curValue, value) || (curValue == null && !containsKey(key))) { return false; } remove(key); return true; } JDK8默认方法,仅当当前key存在且对应的value不为空且和指定的旧值相等,put新值 default boolean replace(K key, V oldValue, V newValue) { Object curValue = get(key); if (!Objects.equals(curValue, oldValue) || (curValue == null && !containsKey(key))) { return false; } put(key, newValue); return true; } JDK8默认方法,仅当当前key存在或对应的value不为空,put新值 default V replace(K key, V value) { V curValue; if (((curValue = get(key)) != null) || containsKey(key)) { curValue = put(key, value); } return curValue; } JDK8默认方法,当key不存在或者对应的value为null时,使用指定的行为,传入一个参数,返回一个结果值, 返回结果值不为null,put新值,返回添加的新值,否则返回不为空的旧值 default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { Objects.requireNonNull(mappingFunction); V v; if ((v = get(key)) == null) { V newValue; if ((newValue = mappingFunction.apply(key)) != null) { put(key, newValue); return newValue; } } return v; } JDK8默认方法,与computeIfAbsent类似,不过该方法需要指定的行为参数,key和旧值,返回新值 default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); V oldValue; if ((oldValue = get(key)) != null) { V newValue = remappingFunction.apply(key, oldValue); if (newValue != null) { put(key, newValue); return newValue; } else { remove(key); return null; } } else { return null; } } JDK8默认方法,提供两个参数的行为函数,用于生成新值,如果新值为空,旧值不为空或包含key,删除key; 如果新值不为空,put进map,返回新值; default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); V oldValue = get(key); V newValue = remappingFunction.apply(key, oldValue); if (newValue == null) { // delete mapping if (oldValue != null || containsKey(key)) { // something to remove remove(key); return null; } else { // nothing to do. Leave things as they were. return null; } } else { // add or replace old mapping put(key, newValue); return newValue; } } JDK8默认方法,提供key,value(想更新的值)以及两个参数的行为函数,如果旧值weinull,新值直接使用提供的value, 否则,通过行为函数,传入旧值和指定的value来生成对应的新值; 如果新值为null,删除原map的key;否则,put新值到map中 default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Objects.requireNonNull(value); V oldValue = get(key); V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value); if(newValue == null) { remove(key); } else { put(key, newValue); } return newValue; } }