java迭代器原理及迭代map的四種方式
迭代器原理:
什麼是迭代器,使用迭代器的好處?
迭代器就是用來遍歷集合中對象的東西,也就是說,對於集合,我們不像對原始數組那樣通過直接訪問元素來迭代的,而是通過迭代器來遍歷對象。這麼做的好處是將對於集合類型的遍歷行為與被遍歷集合對象分離,這樣以來,就不需要關心該集合類型的具體實現是怎麼樣的。隻要獲取這個集合對象的迭代器便可以遍歷這個集合中的對象。而像遍歷對象順序以及怎麼訪問對象元素這些細節,全部由它自己的迭代器來處理。
迭代器怎麼實現的?
首先集合要先實現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內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java map為什麼不能遍歷的同時進行增刪操作
- Java中遍歷Map集合的5種方式總結
- Java List的remove()方法踩坑
- 分析Java中Map的遍歷性能問題
- 淺談HashMap中7種遍歷方式的性能分析