文章目录
- 1. HashMap数据结构
- 1.1 数组+单向链表+红黑树
- 1.2 指定初始容量,省去多次扩容步骤
- 1.3 获取map内容:Map.Entry
- 2. 遍历集合时删除元素
- 3. computeIfAbsent()方法
1. HashMap数据结构
jdk是1.8版本
HashMap 线程不安全
ConcurrentHashMap 线程安全
1.1 数组+单向链表+红黑树
元素放入hashmap中,放入node节点中,nodel节点有四个字段key value next hash,当两个元素的key通过hash算法得到的hash值相同时就会存入单向链表中。hashmap初始值是16,负载因子是0.75,得到阈值是12,当元素超过12就会扩容,当数组长度超过64并且单向链表长度超过8就会将单向链表转为红黑树,当红黑树数据量小于6就会再转为单向链表
jdk1.8 之前 HashMap 由 数组 + 链表 组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突(两个对象调用的 hashCode 方法计算的哈希值经哈希函数算出来的地址被别的元素占用)而存在的(“拉链法”解决冲突)。jdk1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为 8 )并且当前数组的长度大于 64 时,此时此索引位置上的所有数据改为使用红黑树存储。
1.2 指定初始容量,省去多次扩容步骤
实际工作中对HashMap数据结构的关注点,我们可以放在扩容上;
HashMap初始容量是16,当大于这个值,就会扩容,每次都是扩大成原来的两倍;
所以,如果我们可以估算出我们的map需要多大的容量,在初始化的时候直接指定初始容量值,这样就省略了HashMap一次次扩容的步骤
1.3 获取map内容:Map.Entry
Map.Entry是Java中Map接口的一个内部接口,用于表示Map中的一个实体,即一个键值对(key-value对)。它是一个泛型接口,定义为Entry<K,V>,其中K表示键的类型,V表示值的类型。
你可以使用Map.Entry来遍历Map集合,并获取每个键值对的键和值。下面是一个示例代码:
import java.util.HashMap;
import java.util.Map;
public class MapEntryExample {
public static void main(String[] args) {
Map<Integer, String> maps = new HashMap<>();
maps.put(3, "张飞");
maps.put(2, "关羽");
maps.put(4, "赵云");
maps.put(1, "刘备");
maps.put(5, "马超");
for (Map.Entry<Integer, String> entry : maps.entrySet()) {
System.out.println("key=" + entry.getKey() + " value=" + entry.getValue());
}
}
}
这段代码会输出Map中每个键值对的键和值:
key=1 value=刘备
key=2 value=关羽
key=3 value=张飞
key=4 value=赵云
key=5 value=马超
通过使用Map.Entry,你可以方便地遍历Map集合并获取每个键值对的键和值。
2. 遍历集合时删除元素
遍历集合时删除元素这种场景建议用迭代器处理 或者 再新建一个集合进行存储
public static void main(String[] args) {
Map<Integer, String> stuMap = new HashMap<>();
stuMap.put(1, "xlsj");
stuMap.put(2, "xinliushijian");
stuMap.put(3, "心流时间");
// A: entrySet()、keySet()、values()方法作用
// key:value 集合
Set<Map.Entry<Integer, String>> stuEntrySet = stuMap.entrySet();
// key 集合
Set<Integer> stuKeySet = stuMap.keySet();
// value 集合
Collection<String> stuValues = stuMap.values();
System.out.println(stuEntrySet); // [1=xlsj, 2=xinliushijian, 3=心流时间]
System.out.println(stuKeySet); // [1, 2, 3]
System.out.println(stuValues); // [xlsj, xinliushijian, 心流时间]
// B: 遍历集合时删除元素, 普通for循环、迭代器不会报错,其他会报错,增强for循环其实也是用到迭代器,
// 集合遍历时不可以删除元素,而迭代器可以
// 报错原因如下modCount != expectedModCount
/* final HashMap.Node<K,V> nextNode() {
HashMap.Node<K,V>[] t;
HashMap.Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}*/
// 1.普通for循环遍历时可以删除元素
for (int i = 0; i < stuKeySet.size(); i++) {
if (i == 2) {
stuKeySet.remove(i);
}
}
// 2.for增强循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationException
for (int i : stuKeySet) {
if (i == 2) {
stuKeySet.remove(i);
}
}
// 3.forEach循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationException
stuMap.forEach((k, v) -> {
if (k == 2) {
stuKeySet.remove(k);
}
});
// 4.stream forEach循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationException
stuKeySet.stream().forEach(k -> {
if (k == 2) {
stuKeySet.remove(k);
}
});
// 5.迭代器遍历时可以删除元素
Iterator integers = stuEntrySet.iterator();
while (integers.hasNext()) {
Map.Entry<Integer, String> entry = (Map.Entry<Integer, String>) integers.next();
System.out.println(entry.getKey());
if (entry.getKey() == 2) {
integers.remove();
}
}
System.out.println(stuMap);
}
3. computeIfAbsent()方法
key不存在或者value为null时,使用put给定的值
public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
map.put("xin", list);
map.put("xi", new ArrayList<>());
map.put("x", null);
// jing这个key不存在或者对应的value不存在,则put给的值
List<String> list1 = map.computeIfAbsent("jing",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
List<String> list2 = map.computeIfAbsent("xin",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
List<String> list3 = map.computeIfAbsent("xi",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
List<String> list4 = map.computeIfAbsent("x",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
System.out.println(list1);
System.out.println(list2);
System.out.println(list3);
System.out.println(list4);
System.out.println("---------------jing--------------");
System.out.println(map.get("jing"));
map.putIfAbsent("jing1", Arrays.asList(new String[]{"DE1", "BU1", "DE1"}));
System.out.println("---------------jing1--------------");
System.out.println(map.get("jing1"));
}
打印
[DE, BU, DE]
[a, b, c]
[]
[DE, BU, DE]
---------------jing--------------
[DE, BU, DE]
---------------jing1--------------
[DE1, BU1, DE1]