java迭代器原理及迭代map的四种方式
作者:dandeseed
迭代器原理:
什么是迭代器,使用迭代器的好处?
迭代器就是用来遍历集合中对象的东西,也就是说,对于集合,我们不像对原始数组那样通过直接访问元素来迭代的,而是通过迭代器来遍历对象。这么做的好处是将对于集合类型的遍历行为与被遍历集合对象分离,这样以来,就不需要关心该集合类型的具体实现是怎么样的。只要获取这个集合对象的迭代器便可以遍历这个集合中的对象。而像遍历对象顺序以及怎么访问对象元素这些细节,全部由它自己的迭代器来处理。
迭代器怎么实现的?
首先集合要先实现iterable接口来表示此对象是可以进行迭代的。而实现iterable接口的对象实现了iterator方法,这个方法返回了一个Iterator对象。一个迭代器对象需要Iterator接口中的方法:hasNext(),next(),remove()。remove()方法会删除最近一次调用的元素,如果remove()之前没有调用next()的话直接调用remove()会产生报错信息(IllegalStateException)。我们在进行对集合对象迭代的时候,next()会返回当前对象第一个对象并返回,然后next会指向下一个元素,hasNext方法就是看这个指针后面还有没有元素了。
迭代器的陷阱?
使用for迭代的时候不可以使用集合进行remove操作。这时候需要使用迭代器进行迭代,然后使用迭代器中的remove方法进行删除。
为什么会产生这样的错误?
remove()方法在删除元素的时候,还会修改一个修改次数的标志位modCount,如果iterator的expectedModCount与modCount的大小不相等时,会抛出一个ConcurrentModificationException异常。modCount的目的主要是为了防止当前对象迭代过程中存在其他线程对当前对象的修改。
// iterable接口源代码
public interface Iterable<T> { /** * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */ Iterator<T> iterator(); default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } }
// iterator接口源代码
public interface Iterator<E> { /** * 如果迭代拥有更多元素,那么返回true */ boolean hasNext(); /** * 返回iteration中的下一个元素 */ E next(); /** * 如果删除一个集合中的元素没有调用这个方法,二十直接中集合中删除,那么这个迭代器的行为没有被指定 */ default void remove() { throw new UnsupportedOperationException("remove"); } /** * 遍历集合中的剩余元素(如果之前调用了两次next()那么只会遍历集合中剩余元素 * 使用案例: * Iterator<Integer> it = map.keySet().iterator(); it.next(); it.next(); it.forEachRemaining(System.out::println); */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
HashMap中实现迭代的核心代码:
final Node<K,V> nextNode() { Node<K,V>[] t; Node<K,V> e = next; // 对象属性中的next是下一个值 if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); // next = e.next 如果e.next为null,那么继续找数组下一个不为null的值 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;
遍历map的四种方式
import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.HashMap; public class MapTest { public static void main(String[] args) { HashMap<Integer,Integer> map = new HashMap(); map.put(0,1); map.put(2,2); map.put(1,2); map.put(4,5); map.put(3,4); // 遍历hashmap entry foreach Set<Map.Entry<Integer,Integer>> ent = map.entrySet(); for(Map.Entry<Integer,Integer> entry:ent){ System.out.println(entry.getKey()+" : "+entry.getValue()); //map.remove(0); } System.out.println(); // 通过keySet或者values()遍历 Set<Integer> set = map.keySet(); for(Integer key:set){ System.out.println(key+" -- "+map.get(key)); } Collection<Integer> set1 = map.values(); for(Integer val:set1){ System.out.println(val); } System.out.println(); // iterator原理是什么 通过iterator遍历map Iterator<Map.Entry<Integer,Integer>> iter = map.entrySet().iterator(); while(iter.hasNext()){ Map.Entry entry = iter.next(); System.out.println(entry.getKey()+" : "+entry.getValue()); iter.remove(); } System.out.println(); Iterator<Integer> keys = map.keySet().iterator(); while(keys.hasNext()){ int k = keys.next(); System.out.println(k+" -- "+ map.get(k)); } } }
参考链接:https://blog.csdn.net/fuzhongmin05/article/details/72460658
到此这篇关于java迭代器原理及迭代map的四种方式的文章就介绍到这了,更多相关java迭代map内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!