Map、AbstractMap
Map是一个有键值映射的,但不包括相同key,每个key至多对应一个value。
这个接口替代了Dictionary这个类,Dictionary是抽象类而非接口.
除了一些基本的方法。只要看一下JDK1.8新增的方法
getOrDefault(Object key, V defaultValue)
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
返回指定键映射到的值,如果此映射不包含键的映射,则返回 defaultValue 。
public static void main(String[] args) {
Map<String,String> m=new HashMap<String,String>(3);
m.put("1","1");
m.put("2","2");
m.put("3","3");
String orDefault = m.getOrDefault("4", "4");
System.out.println(orDefault);
}
forEach(BiConsumer<? super K, ? super V> 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);
}
}
m.forEach((k,v)->System.out.println(k+"-"+v));
replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
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);
}
}
}
对于map中每一个entry,将其value替换成BiFunction接口返回的值.直到所有entry替换完or出现异常为止.如果执行过程中出现异常,则抛给调用者
m.replaceAll((k,v)->{
if(k.equals("4")) {
v="";
}
return v;
});
m.forEach((k,v)->System.out.println(k+"-"+v));
putIfAbsent(K key, V value)
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
如果指定的键尚未与某个值相关联(或映射到 null
), null
其与给定值相关联并返回 null
,否则返回当前值。
remove(Object key, Object value)
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在map中是一个entry,则删除这个entry
replace(K key, V oldValue, V 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在map中有entry,则为指定key的entry,用新value替换旧的value.
replace(K key, V value)
default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}
如果指定key在map中有value,则用参数value进行替换
computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction)
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;
}
若lambda式返回值!=null,且Key不存在,则在map中新增该组(K,V);且若Key存在,且原value!=null,则不做操作;但原value=null,则更新value值;
m.computeIfAbsent("5", v -> "5");
m.forEach((k, v) -> System.out.println(k + "-" + v));
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
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;
}
}
对指定的在map中已经存在的key的value进行操作。只对已经存在key的进行操作,其他不操作。
m.computeIfPresent("1", (k,v) -> "5");
m.computeIfPresent("7", (k,v) -> "7");
m.forEach((k, v) -> System.out.println(k + "-" + v));
注意jdk8中不要尝试对ConcurrentHashMapz类中的computeIfAbsent方法使用递归,会导致一个bug,产生死循环https://mp.weixin.qq.com/s/O6UmB7YDKIYtNvqCOjNwDQ
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
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;
}
}
计算K,V之间映射关系,根据重映射函数返回新的V值,若返回null,直接删除该组映射.(如果最初不存在则保持不存在)。 如果重映射函数本身引发(未检查)异常,则重新引导异常,并且当前映射保持不变。BiFunction接口的apply的入参为key、oldValue
m.compute("1", (k,v)->k.length()==v.length()?null:v);
// m.compute("1", (k,v)->k.length()!=v.length()?null:"33");
m.forEach((k, v) -> System.out.println(k + "-" + v));
merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
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;
}
如果指定的键尚未与值相关联或与null相关联,则将其与给定的非空值相关联。 否则,将关联值替换为给定重映射函数的结果,如果结果为null ,则将其null 。如果重映射函数返回null ,则映射将被删除。 如果重映射函数本身引发(未检查)异常,则重新引导异常,并且当前映射保持不变。
m.merge("1", "in", (k,v)->k+v.toUpperCase());
m.merge("2", "in", (k,v)->null);
m.merge("3", "on", (k,v)->"ff");
m.forEach((k, v) -> System.out.println(k + "-" + v));
AbstractMap
AbstractMap类和AbstractList类一样,都是一种模板类,提供了Map的基本实现。开发人员如果想实现自己的Map,只需要继承AbstractMap类,实现特定方法即可。
我们要实现一个不可变的 Map 时,只需要继承 AbstractMap 类并实现 entrySet() 即可。
如果想要实现一个可变的 Map ,我们还需要重写 put() 方法,因为 AbstractMap 类中默认不支持 put实现,子类必须重写该方法的实现,否则会抛出异常:
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
Set<Map.Entry<K,V>> entrySet();
public abstract Set<Map.Entry<K,V>> entrySet();
也就是说所有的子类都必须实现entrySet()
方法。纵观AbstractMap中的成员方法内部实现,基本都依赖于entrySet()
方法,它返回了Map所保存的键值对。Map集合没有Iterator,如果要去除元素,必须将Map集合转换成Set集合依赖也是entrySet()。
两个成员变量
//Map中所有的键
transient Set<K> keySet;
//Map所有的值
transient Collection<V> values;
//都是不可序列化的
Set keySet();、Collection values()
这个两个方法没有采用遍历Entry的方式,而是重写了iterator,再调用Entry集合的迭代器。
SimpleEntry、SimpleImmutableEntry两个子类
唯一区别setValue 这个方法。SimpleEntry 支持 setValue 的操作实现,而SimpleImmutableEntry 就没有实现,前者为可变集合,后者为不可变集合。