今日学习内容总结如下:
Map接口
哈希表就是一种以键-值(key-indexed) 存储数据的结构,只要输入待查找的值即key,即可查找到其对应的值。
哈希的思路很简单,如果所有的键hashCode都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。
它提供了一组键值的映射。其中存储的每个数据对象都有一个相应的键key,键决定了值对象在Map中的存储位置。键应该是唯一的,不允许重复,每个key只能映射一个value。
Map接口的定义
public interface Map<K, V>
表示存储数据时有2个部分key和value,key不允许重复
int size(); 获取key-value个数
boolean containsKey(Object key);判断集合中是否包含指定的key值
要求key类型需要实现equals和hashCode发方法
首先调用hashCode方法获取key对应的hash值,然后当key值和map中的key值相同时才会继续调用equals进行等值判断,否则是false
boolean containsValue(Object value);判断集合中是否包含指定的value值
要求value类型需要实现equals,对于hashCode没有要求;进行判断时是直接调用equals方法
V get(Object key);根据key值获取对应的value值
如果key不存在,则返回为null;即使key值不存在也不会抛异常
获取数据返回为null有2种情形:没有对应的key,存储key对应的值为null
V put(K key, V value);向map集合中添加key-value对,返回原始存储的value值
如果key值已经存在则后盖前,同时返回被覆盖的数据
要求针对key类型必须实现equals和hashCode两个方法
Java的潜规则:要求当两个对象的equals为true时,hashCode值必须相等
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A3 other = (A3) obj;
return Objects.equals(id, other.id) && Objects.equals(name, other.name);
}
V remove(Object key); 根据key值删除对应的key-value对,返回对应的value值
如果key值不存在,不会抛出异常,只是返回值为null;如果key值存在则返回对应的value
获取数据返回为null有2种情形:没有对应的key,存储key对应的值为null
void clear();清空集合中的所有元素key-value对
遍历map集合有三种方式,map提供了三种不同的视图
1、Iterator 2、.forEach(lambda) 3、for-each结构 for(Object tmp: map.keySet)
Set<K> keySet();获取所有的key所组成的Set集合
Collection<V> values();获取所有的value所组成的Collection集合
Set<Map.Entry<K, V>> entrySet();获取所有的key-value对所构成的Set集合
在Map中一个key-value被封装成一个Entry的对象
interface Entry<K, V> {
K getKey(); 当前entry对象中存储的key值
V getValue(); 当前entry对象中存储的value值
V setValue(V value); 修改entry对象中所存储的value值
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());
}
}
新增方法:
按照key值获取key所对应的value值,如果key值不存在则返回defaultValue;
如果key存在,即使值为null,也是返回value值,不是defaultValue
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
遍历当前Map集合中的所有元素
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action); //判断非action非空,如果action为null则抛出异常
for (Map.Entry<K, V> entry : entrySet()) { for-each结构
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise) {
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
对应的lambda表达式接口定义为
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
可以使用lambda表达式修改Map中所有的value值
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function); 要求function参数非空,否则异常
for (Map.Entry<K, V> entry : entrySet()) {for-each结构用于遍历所有的key-value对
K k;
V v;
try {
k = entry.getKey(); 获取当前entry对象中的key值
v = entry.getValue(); 获取当前entry对象中的value值
} catch (IllegalStateException ise) {
throw new ConcurrentModificationException(ise);
}
v = function.apply(k, v);调用BiFunction中的方法对key和value进行处理,并返回一个V类型的数据
try {
entry.setValue(v);将计算得到的新数据注入到entry对象中,实现数据的修改
} catch (IllegalStateException ise) {
throw new ConcurrentModificationException(ise);
}
}
}
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u); //针对传入的t和u进行处理,可以返回一个新的类型数据
}
按照key值修改原始数据,如果key对应的值为空,则修改数据为value,否则返回旧有数据,不修改
default V putIfAbsent(K key, V value) {
V v = get(key); //首先按照key获取对应的value值
if (v == null) { //如果获取的value为空,则修改key对应的值为参数value
v = put(key, value);
}
return v; //返回v值,如果v非空则返回原始数据,如果v为空则返回value
}
按照key和value值执行删除操作
default boolean remove(Object key, Object value) {
Object curValue = get(key); //获取key对应的原始数据
//如果原始存储的数据和value参数不相等或者不存在对应的key并且key对应存储的原始数据为null,//则不执行任何操作
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key); //删除key对应的数据
return true;
}
按照指定的key和oldValue值执行替换操作,将key对应的值修改为newValue
default boolean replace(K key, V oldValue, V newValue) {
Object curValue = get(key); //按照key获取对应的当前存储的value值
//如果当前存储的值和oldValue参数值不相等或者当前值为null并且不包含当前的key,则直接返回
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
put(key, newValue); //修改key所对应的value为newValue
return true;
}
按照指定的key进行修改,要求key对应的value非空或者包含对应的key
default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}