概述
前言
在开发中,经常使用的集合就是 ArrayList 和 HashMap,在一些需要排序的场景中,可能需要使用 TreeSet 和 TreeMap 等,其余的集合类有的由于长时间不适用,已经忘记了其特性和应用场景,所以在这里重新总结一下,方便以后复习。
Java 集合体系
Iterator 接口遍历
Iterator 也是 Java 集合框架中的一员,被称为迭代器。
主要用的方法就是:
- hasNext()
- next()
- remove()
并且 Iterator 只提供遍历,并不提供存储元素的集合。
当使用 Iterator 迭代遍历集合时,不能对集合里的元素进行修改,只能通过迭代器的 remove( ) 方法去删除才可以,否则会引发 java.util.ConcurrentModificationException 异常。
例如:
public class IteratorTest {
public static void main(String[] args) {
Collection<String> books = new HashSet<>();
books.add("高性能MySQL");
books.add("深入理解Java虚拟机");
books.add("鸟哥的Linux私房菜");
Iterator<String> it = books.iterator();
while (it.hasNext()) {
String bookName = it.next();
System.out.println(bookName);
if (bookName.contains("Java")) {
books.remove(bookName);
}
}
}
}
------------------------------------------------------------------------
高性能MySQL
深入理解Java虚拟机
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)
at java.util.HashMap$KeyIterator.next(HashMap.java:1461)
at com.beng.list.IteratorTest.main(IteratorTest.java:17)
Iterator 采用快速失败(fast-fail)机制,一旦检测在迭代过程中该集合已经被修改,立即引发异常处理。
我们是使用 HashSet 出现的该异常,看一下 HashSet 如何获取的迭代器。
/**
* Returns an iterator over the elements in this set. The elements
* are returned in no particular order.
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
我们知道 HashSet 是基于 HashMap 的,其调用了 HashMap 的 keySet 的 iterator() 方法
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
KeySet 是 HashMap 的一个内部类
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
public final Iterator iterator() { return new KeyIterator(); }
KeyIterator 也是 HashMap 的一个内部类,并且继承了 HashIterator
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
HashIterator 同样是 HashMap 的一个内部抽象类,并且实现了 Iterator 的三个方法
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
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;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
当调用 next() 时,就会调用 nextNode 方法
final Node<K,V> nextNode() {
Node<K,V>[] t;
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;
}
如果 modCount != expectedModCount 就会启动快速失败机制,抛出异常。
modCount 表示集合修改的次数,当调用 add() 和 remove() 方法 时,都会 modCount++。
最后
以上就是无心音响为你收集整理的Java 集合总结以及 java.util.ConcurrentModificationException 异常分析的全部内容,希望文章能够帮你解决Java 集合总结以及 java.util.ConcurrentModificationException 异常分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复