java迭代器原理及迭代map的四種方式
迭代器原理:
什么是迭代器,使用迭代器的好處?
迭代器就是用來(lái)遍歷集合中對(duì)象的東西,也就是說(shuō),對(duì)于集合,我們不像對(duì)原始數(shù)組那樣通過直接訪問元素來(lái)迭代的,而是通過迭代器來(lái)遍歷對(duì)象。這么做的好處是將對(duì)于集合類型的遍歷行為與被遍歷集合對(duì)象分離,這樣以來(lái),就不需要關(guān)心該集合類型的具體實(shí)現(xiàn)是怎么樣的。只要獲取這個(gè)集合對(duì)象的迭代器便可以遍歷這個(gè)集合中的對(duì)象。而像遍歷對(duì)象順序以及怎么訪問對(duì)象元素這些細(xì)節(jié),全部由它自己的迭代器來(lái)處理。
迭代器怎么實(shí)現(xiàn)的?
首先集合要先實(shí)現(xiàn)iterable接口來(lái)表示此對(duì)象是可以進(jìn)行迭代的。而實(shí)現(xiàn)iterable接口的對(duì)象實(shí)現(xiàn)了iterator方法,這個(gè)方法返回了一個(gè)Iterator對(duì)象。一個(gè)迭代器對(duì)象需要Iterator接口中的方法:hasNext(),next(),remove()。remove()方法會(huì)刪除最近一次調(diào)用的元素,如果remove()之前沒有調(diào)用next()的話直接調(diào)用remove()會(huì)產(chǎn)生報(bào)錯(cuò)信息(IllegalStateException)。我們?cè)谶M(jìn)行對(duì)集合對(duì)象迭代的時(shí)候,next()會(huì)返回當(dāng)前對(duì)象第一個(gè)對(duì)象并返回,然后next會(huì)指向下一個(gè)元素,hasNext方法就是看這個(gè)指針后面還有沒有元素了。
迭代器的陷阱?
使用for迭代的時(shí)候不可以使用集合進(jìn)行remove操作。這時(shí)候需要使用迭代器進(jìn)行迭代,然后使用迭代器中的remove方法進(jìn)行刪除。
為什么會(huì)產(chǎn)生這樣的錯(cuò)誤?
remove()方法在刪除元素的時(shí)候,還會(huì)修改一個(gè)修改次數(shù)的標(biāo)志位modCount,如果iterator的expectedModCount與modCount的大小不相等時(shí),會(huì)拋出一個(gè)ConcurrentModificationException異常。modCount的目的主要是為了防止當(dāng)前對(duì)象迭代過程中存在其他線程對(duì)當(dāng)前對(duì)象的修改。
// 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中的下一個(gè)元素 */ E next(); /** * 如果刪除一個(gè)集合中的元素沒有調(diào)用這個(gè)方法,二十直接中集合中刪除,那么這個(gè)迭代器的行為沒有被指定 */ default void remove() { throw new UnsupportedOperationException("remove"); } /** * 遍歷集合中的剩余元素(如果之前調(diào)用了兩次next()那么只會(huì)遍歷集合中剩余元素 * 使用案例: * 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中實(shí)現(xiàn)迭代的核心代碼:
final Node<K,V> nextNode() { Node<K,V>[] t; Node<K,V> e = next; // 對(duì)象屬性中的next是下一個(gè)值 if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); // next = e.next 如果e.next為null,那么繼續(xù)找數(shù)組下一個(gè)不為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
到此這篇關(guān)于java迭代器原理及迭代map的四種方式的文章就介紹到這了,更多相關(guān)java迭代map內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java高并發(fā)情況下高效的隨機(jī)數(shù)生成器
這篇文章主要介紹了java高并發(fā)情況下高效的隨機(jī)數(shù)生成器,對(duì)于性能有要求的同學(xué),可以參考下2021-04-04java結(jié)合keytool如何實(shí)現(xiàn)非對(duì)稱簽名和驗(yàn)證詳解
這篇文章主要給大家介紹了關(guān)于java結(jié)合keytool如何實(shí)現(xiàn)非對(duì)稱簽名和驗(yàn)證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08使用idea遠(yuǎn)程調(diào)試jar包的配置過程
這篇文章主要介紹了使用idea遠(yuǎn)程調(diào)試jar包的配置過程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09Android讀取本地或網(wǎng)絡(luò)圖片并轉(zhuǎn)換為Bitmap
這篇文章主要為大家詳細(xì)介紹了Android讀取本地或網(wǎng)絡(luò)圖片,并轉(zhuǎn)換為Bitmap,感興趣的小伙伴們可以參考一下2016-08-08mybatis-plus分頁(yè)查詢?nèi)N方法小結(jié)
本文主要介紹了mybatis-plus分頁(yè)查詢?nèi)N方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05bug解決Failed_to_execute_goal_org.springframework
這篇文章主要為大家介紹了bug解決Failed_to_execute_goal_org.springframework,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09spring boot中xalan引入報(bào)錯(cuò)系統(tǒng)找不到指定的文件原因分析
這篇文章主要介紹了spring boot中xalan引入報(bào)錯(cuò)系統(tǒng)找不到指定的文件,主要原因是內(nèi)嵌的tomcat9.0.36,本文給大家分享最新解決方法,需要的朋友可以參考下2023-08-08springboot中縮短一個(gè)url鏈接的實(shí)現(xiàn)
縮短 URL 是現(xiàn)代應(yīng)用程序中常見的需求,通常用于減少長(zhǎng) URL 的長(zhǎng)度,使其更易于分享,URL 縮短服務(wù)的核心思路是將長(zhǎng) URL 映射到一個(gè)唯一的短代碼,本文主要介紹了springboot中縮短一個(gè)url鏈接的實(shí)現(xiàn),感興趣的可以了解一下2024-09-09