JDK8源码系列--Map接口与Dictionary抽象类

package java.util;

一、Map接口

1 接口定义

public interface Map<K,V>

Map是存放键值对的数据结构。map中没有重复的key,每个key最多只能映射一个value。map不允许包含自身引用作为key。Map接口用来代替Dictionary抽象类。

Map接口提供了三种集合视图。map默认顺序是其集合视图迭代器遍历元素的顺序,例如HashMap。TreeMap自定义顺序。

2 抽象方法

2.1 查询操作(5个)

// 返回map中键值对个数。
// 如果map元素个数多于Integer.MAX_VALUE,返回Integer.MAX_VALUE。
int size();

// map中存在键值对,返回true
boolean isEmpty();

// map中存在指定key的映射,返回true。
boolean containsKey(Object key);

// map中存在一个或多个key映射到指定value,返回true。
// 性能可能为O(n),n为元素个数。
boolean containsValue(Object value);

// 获取指定key的映射值
// 通常值存在返回值,值不存在返回null
V get(Object key);

2.2 修改单个元素(2个)

// 向map中插入键值对,若已存在,则更新。
V put(K key, V value);

// 删除map中指定key的键值对。若不存在,返回null。
V remove(Object key);

2.3 修改所有元素(2个)

// 拷贝map中所有映射到当前map中
// 拷贝过程中,参数map被修改,结果不确定。
void putAll(Map<? extends K, ? extends V> m);

// 删除map中所有映射
void clear();

2.4 集合视图(3个)

// 返回map中key的集合视图
Set<K> keySet();

// 返回map中值的集合视图。
Collection<V> values();

// 返回map中entry的集合视图
Set<Map.Entry<K, V>> entrySet();

集合视图依赖于当前map。如果修改map中映射,就会在视图中有所体现。如果在对集合视图迭代的同时修改了map(迭代器自身的操作除外),迭代结果是不确定的。三种集合视图均支持元素的删除,可以通过Iterator.remove、Collection/Set.remove、removeAll、retainAll 和 clear 操作从map中删除对应的键值对。均不支持添加add和addAll操作。

内部接口Entry
entry即键值对,Map.entrySet()返回的就是entry的集合,是获取entry引用的唯一途径。Map.Entry对象只在迭代过程中有效。

interface Entry<K,V> {
    // 返回entry的key
    K getKey();

    // 获取entry的value
    V getValue();

    // 设定新值
    V setValue(V value);

    // 比较当前entry与指定对象
    boolean equals(Object o);

    // 计算当前entry的hashcode
    int hashCode();

    // 比较器--使用自然排序的key比较Map.Entry
    // 1.8增加
    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());
    }

    // 比较器--使用自然排序的value比较Map.Entry
    // 1.8增加
    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());
    }

    // 比较器--使用给定key比较器比较Map.Entry
    // 1.8增加
    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());
    }

    // 比较器--使用给定value比较器比较Map.Entry
    // 1.8增加
    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());
    }
}

2.5 比较和hash(2个)

// 比较当前map与给定对象
boolean equals(Object o);

// 获取当前map的哈希值,值等于map中每个entry哈希值的和。
int hashCode();

3 默认方法(1.8增加)

JDK8中增加几个默认方法,默认方法主要针对某些操作的实现,减少代码编写量。默认方法也结合了函数接口和lambda表达式进行实现。需要注意的是,默认方法实现是线程不安全的,并发场景使用需要重写。

default V getOrDefault(Object key, V defaultValue) {
    V v;
    return (((v = get(key)) != null) || containsKey(key))
        ? v
        : defaultValue;
}

返回指定key的映射值,若无,返回默认值。

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) {
            // 表示当前entry已经不再map中了。
            throw new ConcurrentModificationException(ise);
        }
        action.accept(k, v);
    }
}

对map中每个entry执行给定BiConsumer函数操作,直到执行完,或抛异常。除非实现类特别指定,遍历顺序按照entry set迭代顺序。
操作的异常会抛给调用者。迭代过程中,存在entry被删除,抛出ConcurrentModificationException。

default V putIfAbsent(K key, V value)

若指定key的映射值为null,设定值为参数值。不为null,则返回当前值。

default boolean remove(Object key, Object value)

删除<指定key, 指定value>entry。

default V replace(K key, V value)

指定key映射值替换为新值。

default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)

对于每个entry,替换值为指定BiFuntion接口返回结果,直到替换完,或抛出异常。过程异常抛给调用者。迭代过程中,存在entry被删除,抛出ConcurrentModificationException。

default boolean replace(K key, V oldValue, V newValue)

如果指定key映射指定oldValue,则替换值为newValue。如果老值为null不会抛出NullPointerException,除非新值也为null。

default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction) 

若指定key的映射值为null,尝试使用指定函数式接口计算映射值。
如果接口计算值返回为null,不记录映射。如果计算抛出未检查异常,异常会被再次抛出,也不记录映射。

default V computeIfPresent(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction)

若指定key的映射值存在且非空,尝试使用指定函数式接口计算映射值。
若计算所得到映射值为null,删除该映射;如果计算抛出异常,异常会再次抛出,当前映射保持不变。

default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction)

利用当前entry的key和value,计算新的映射值。
如果新值不为空,添加/更新map;新值为null,老值不为空,则删除该映射;老值为空,则当前映射不变。

default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction)

如果指定key没有映射或映射值为null,设定其映射为给定value。
如果已有映射值,利用函数式接口对其重新映射。若计算结果为null,删除该映射。

二、Dictionary抽象类

Dictionary类是废弃类,已知子类有HashTable。新的实现都是实现Map接口。

public abstract
class Dictionary<K,V> {

    public Dictionary() {
    }

    abstract public int size();
    abstract public boolean isEmpty();
    abstract public Enumeration<K> keys();
    abstract public Enumeration<V> elements();
    abstract public V get(Object key);
    abstract public V put(K key, V value);
    abstract public V remove(Object key);
}
发布了17 篇原创文章 · 获赞 41 · 访问量 9998

猜你喜欢

转载自blog.csdn.net/awecoder/article/details/93394654