Java HashMap EntrySet 内部类 的 forEach 方法 分析
forEach()
该方法签名为void forEach(BiConsumer<? super K,? super V> action), 作用是对Map中的每个映射执行action指定的操作, 其中BiConsumer是一个函数接口, 里面有一个待实现方法void accept(T t, U u)。 BinConsumer接口名字和accept()方法名字都不重要,请不要记忆他们。
源码
HashMap 的 forEach
代码语言:javascript复制// 作用是对Map中的每个映射执行action指定的操作,
// 其中BiConsumer是一个函数接口,
// 里面有一个待实现方法void accept(T t, U u)
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
// 哈希表底层 tab
Node<K,V>[] tab;
// 空的 action 过滤 抛异常
if (action == null)
throw new NullPointerException();
// 过滤 tab 的合法性 顺便 赋个值 tab = table
if (size > 0 && (tab = table) != null) {
// 结构调整的次数哦 modCount
int mc = modCount;
// 遍历 tab
for (int i = 0; i < tab.length; i) {
// 遍历 哈希表上的 链表或 红黑树
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key, e.value);
}
// 遍历过程中 hashMao 结构发生了调整
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
EntrySet 的 forEach
其实是我写错了,本来应该 分析 HashMap 的结果源码找错了位置强行 分析了 这里的
代码语言:javascript复制// forEach 遍历HashMap的元素
// final 代表不可修改 在这个方法也没有返回值
// 传进来的参数有 Consumer<? super Map.Entry<K,V>> 是一个 action
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
// tab就是存储的底层哈希表
Node<K,V>[] tab;
// action 如果是空的就没法遍历了
if (action == null)
throw new NullPointerException();
// 判断 这个 tab 是 合法的 size 大于零 tab 赋值 table 的引用 判断不为空
// 生产环境这样写代码会被打死
if (size > 0 && (tab = table) != null) {
// mc 是 记录 调整的次数
// The number of times this HashMap has been structurally modified
int mc = modCount;
// 遍历整个 hash 表
for (int i = 0; i < tab.length; i) {
// for 循环 遍历 tab[i]
// 从生产者 方 接收数据
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e);
}
// 发生了 哈希表 结构的调整
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}