Map
Map是一种用于快速查找的数据布局,它以键值对的形式存储数据,每一个键都是独一的,且对应着一个值,假如想要查找Map中的数据,只需要传入一个键,Map会对键举办匹配并返回键所对应的值,可以说Map其实就是一个存放键值对的荟萃。Map被各类编程语言遍及利用,只不外在名称上大概会有些夹杂,像Python中叫做字典(Dictionary),也有些语言称其为关联数组(Associative Array),但其实它们都是一样的,都是一个存放键值对的荟萃。至于Java中常常用到的HashMap也是Map的一种,它被称为散列表,关于散列表的细节我会在本文中表明HashMap的源码时提及。
Java还提供了一种与Map密切相关的数据布局:Set,它是数学意义上的荟萃,特性如下:
很明明,Map中的key就很切合这些特性,Set的实现其实就是在内部利用Map。譬喻,HashSet就界说了一个范例为HashMap的成员变量,向HashSet添加元素a,等同于向它内部的HashMap添加了一个key为a,value为一个Object工具的键值对,这个Object工具是HashSet的一个常量,它是一个虚拟值,没有什么实际寄义,源码如下:
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
小插曲事后,让我们接着说Map,它是JDK的一个顶级接口,提供了三种荟萃视图(Collection Views):包括所有key的荟萃、包括所有value的荟萃以及包括所有键值对的荟萃,Map中的元素顺序与它所返回的荟萃视图中的元素的迭代顺序相关,也就是说,Map自己是不担保有序性的,虽然也有破例,好比TreeMap就对有序性做出了担保,这主要因为它是基于红黑树实现的。
所谓的荟萃视图就是由荟萃自己提供的一种会见数据的方法,同时对视图的任何修改也会影响到荟萃。比如Map.keySet()返回了它包括的key的荟萃,假如你挪用了Map.remove(key)那么keySet.contains(key)也将返回false,再好比说Arrays.asList(T)可以把一个数组封装成一个List,昆山软件开发,这样你就可以通过List的API来会见和操纵这些数据,如下列示例代码:
String[] strings = {"a", "b", "c"};
List<String> list = Arrays.asList(strings);
System.out.println(list.get(0)); // "a"
strings[0] = "d";
System.out.println(list.get(0)); // "d"
list.set(0, "e");
System.out.println(strings[0]); // "e"
是不是感受很神奇,其实Arrays.asList()只是将传入的数组与Arrays中的一个内部类ArrayList(留意,它与java.util包下的ArrayList不是同一个)做了一个”绑定“,在挪用get()时会直接按照下标返回数组中的元素,而挪用set()时也会直接修改数组中对应下标的元素。相对付直接复制来说,荟萃视图的利益是内存操作率更高,假设你有一个数组,又很想利用List的API来操纵它,那么你不消new一个ArrayList以拷贝数组中的元素,只需要一点特另外内存(通过Arrays.ArrayList对数组举办封装),原始数据依然是在数组中的,并不会复制成多份。
Map接口类型了Map数据布局的通用API(也含有几个用于简化操纵的default要领,default是JDK8的新特性,它是接口中声明的要领的默认实现,即非抽象要领)而且还在内部界说了Entry接口(键值对的实体类),在JDK中提供的所有Map数据布局都实现了Map接口,下面为Map接口的源码(代码中的注释太长了,根基都是些实现的类型,为了篇幅我就只管省略了)。
package java.util;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;
public interface Map<K,V> {
// 查询操纵
/**
* 返回这个Map中所包括的键值对的数量,假如大于Integer.MAX_VALUE,
* 则应该返回Integer.MAX_VALUE。
*/
int size();
/**
* Map是否为空。
*/
boolean isEmpty();
/**
* Map中是否包括key,假如是返回true,不然false。
*/
boolean containsKey(Object key);
/**
* Map中是否包括value,假如是返回true,不然false。
*/
boolean containsValue(Object value);
/**
* 按照key查找value,假如Map不包括该key,则返回null。
*/
V get(Object key);
// 修改操纵
/**
* 添加一对键值对,假如Map中已含有这个key,那么新value将包围掉旧value,
* 并返回旧value,假如Map中之前没有这个key,那么返回null。
*/
V put(K key, V value);
/**
* 删除指定key并返回之前的value,假如Map中没有该key,则返回null。
*/
V remove(Object key);
// 批量操纵
/**
* 将指定Map中的所有键值对批量添加到当前Map。
*/
void putAll(Map<? extends K, ? extends V> m);
/**
* 删除Map中所有的键值对。
*/
void clear();
// 荟萃视图
/**
* 返回包括Map中所有key的Set,对该视图的所有修改操纵会对Map发生同样的影响,反之亦然。
*/
Set<K> keySet();
/**
* 返回包括Map中所有value的荟萃,昆山软件开发,对该视图的所有修改操纵会对Map发生同样的影响,反之亦然。
*/
Collection<V> values();
/**
* 返回包括Map中所有键值对的Set,对该视图的所有修改操纵会对Map发生同样的影响,昆山软件开发,反之亦然。
*/
Set<Map.Entry<K, V>> entrySet();
/**
* Entry代表一对键值对,类型了一些根基函数以及几个已实现的类函数(各类较量器)。
*/
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
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());
}
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());
}
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());
}
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());
}
}
// 较量和hashing
/**
* 将指定的工具与此Map举办较量是否相等。
*/
boolean equals(Object o);
/**
* 返回此Map的hash code。
*/
int hashCode();
// 默认要领(非抽象要领)
/**
* 按照key查找value,假如该key不存在或便是null则返回defaultValue。
*/
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key)) ? v : defaultValue;
}
/**
* 遍历Map并对每个键值对执行指定的操纵(action)。
* BiConsumer是一个函数接口(具有一个抽象要领的接口,用于支持Lambda),
* 它代表了一个接管两个输入参数的操纵,且不返回任何功效。
* 至于它奇怪的名字,按照Java中的其他函数接口的定名类型,Bi应该是Binary的缩写,意思是二元的。
*/
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);
}
}
/**
* 遍历Map,然后挪用传入的函数function生成新value对旧value举办替换。
* BiFunction同样是一个函数接口,它接管两个输入参数而且返回一个功效。
*/
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);
}
}
}
/**
* 假如指定的key不存在可能关联的value为null,则添加键值对。
*/
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
/**
* 当指定key关联的value与传入的参数value相等时删除该key。
*/
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;
}
/**
* 当指定key关联的value与oldValue相等时,利用newValue举办替换。
*/
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;
}
/**
* 当指定key关联到某个value时举办替换。
*/
default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}
/**
* 当指定key没有关联到一个value可能value为null时,挪用mappingFunction生成值并添加键值对到Map。
* Function是一个函数接口,它接管一个输入参数并返回一个功效,假如mappingFunction返回的功效
* 也为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;
}
/**
* 当指定key关联到一个value而且不为null时,挪用remappingFunction生成newValue,
* 假如newValue不为null,那么举办替换,不然删除该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;
}
}
/**
* remappingFunction按照key与其相关联的value生成newValue,
* 当newValue便是null时删除该key,不然添加可能替换旧的映射。
*/
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;
}
}
/**
* 当指定key没有关联到一个value可能value为null,将它与传入的参数value
* 举办关联。不然,挪用remappingFunction生成newValue并举办替换。
* 假如,newValue便是null,那么删除该key。
*/
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;
}
}
需要留意一点,这些default要领都长短线程安详的,任何担保线程安详的扩展类都必需重写这些要领,譬喻ConcurrentHashMap。