日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java for 迭代器_Java基础-迭代器Iterator与语法糖for-each

發(fā)布時間:2023/12/19 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java for 迭代器_Java基础-迭代器Iterator与语法糖for-each 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

迭代器Iterator與語法糖for-each

一、為什么需要迭代器

設(shè)計(jì)模式迭代器

迭代器作用于集合,是用來遍歷集合元素的對象。迭代器不是Java獨(dú)有的,大部分高級語言都提供了迭代器來遍歷集合。實(shí)際上,迭代器是一種設(shè)計(jì)模式:迭代器模式提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露其內(nèi)部的表示。

迭代器封裝了對集合的遍歷,使得不用了解集合的內(nèi)部細(xì)節(jié),就可以使用同樣的方式遍歷不同的集合。

暴露細(xì)節(jié)的遍歷

要理解封裝遍歷的好處,必須理解暴露細(xì)節(jié)的遍歷帶來的壞處。

以下是兩個不同的集合接口,第一個是自定義集合,第二個是JDK的java.util.Listpublic?interface?IUserDefinedList?{????int?length();????E?getElement(int?index);

}public?interface?List?{????int?size();????E?get(int?index);

}

分別使用for循環(huán)對它們進(jìn)行遍歷://?自定義Listfor?(int?i?=?0,?len?=?ul.length();?i?

System.out.println(ul.getElement(i));

}//?java.util.Listfor?(int?i?=?0,?size?=?ll.size();?i?

System.out.println(ll.get(i));

}

遍歷集合的代碼與具體集合類型緊密耦合,不同類型的集合,必須寫出不同的遍歷代碼,不可重用。緊耦合在良好的代碼設(shè)計(jì)中是大忌,這時需要將遍歷邏輯抽離,封裝。這就是迭代器模式了。

二、封裝遍歷-迭代器面向接口編程

面向接口編程是基本的設(shè)計(jì)原則,迭代器模式將遍歷封裝到接口,然后各個集合類可以以實(shí)現(xiàn)接口,或者組合接口實(shí)現(xiàn)類的方式,將遍歷封裝。

迭代器接口如下:public?interface?Iterator?{????boolean?hasNext();????E?next();

}

然后就可以以統(tǒng)一的方式遍歷集合:Iterator?it?=?aIterator;while(it.hasNext)?{

it.next();

}

因?yàn)榧隙紝?shí)現(xiàn)了Iterator接口,所以以上的遍歷代碼是可以重用的,并且與具體集合類型松耦合。

Java迭代器

Java提供的Iterator原理大致相同:

java迭代器接口

忽略Java8提供的默認(rèn)方法forEachRemaining(),java迭代器多了可以移除上一個元素的remove()方法。

Java集合中有很多迭代器的具體實(shí)現(xiàn),以ArrayList為例:

ArrayList迭代器實(shí)現(xiàn)

ArrayList的迭代器是以內(nèi)部類的方式實(shí)現(xiàn)的,每次調(diào)用List的iterator()方法,都會得到一個基于當(dāng)前ArrayList對象狀態(tài)的迭代器:public?Iterator?iterator()?{????return?new?Itr();

}

next()方法:public?E?next()?{

checkForComodification();????int?i?=?cursor;????if?(i?>=?size)????????throw?new?NoSuchElementException();

Object[]?elementData?=?ArrayList.this.elementData;????if?(i?>=?elementData.length)????????throw?new?ConcurrentModificationException();

cursor?=?i?+?1;????return?(E)?elementData[lastRet?=?i];

}

每次調(diào)用next()方法,都會調(diào)用final?void?checkForComodification()?{???if?(modCount?!=?expectedModCount)????????throw?new?ConcurrentModificationException();

}

檢查所迭代的列表對象是否被修改過,modCount是外部類的一個字段,當(dāng)調(diào)用外部類的add, remove, ensureCapacity等方法,都會改變改字段的值,而expectedModCount是內(nèi)部類Itr初始化迭代器實(shí)例時,使用modeCount賦值的字段。這樣,在使用迭代器過程中,如果對正在迭代的對象調(diào)用了add, remove, ensureCapacity等方法,再去調(diào)用迭代器的next(),就會引發(fā)ConcurrentModificationException異常了。

一個誘發(fā)異常的例子:ArrayList?ls?=?new?ArrayList<>();

Iterator?it?=?ls.iterator();while?(it.hasNext())?{

System.out.println(it.next());

ls.ensureCapacity(10);?//?改變了集合對象modCount的值,下次調(diào)用next?拋出異常}

三、語法糖for-each

java中的for-each:List?ls?=?new?ArrayList<>();for?(String?s:?ls)?{

System.out.println(s);

}

for-each其實(shí)只是java提供的語法糖。語法糖是編程語言提供的一些便于程序員書寫代碼的語法,是編譯器提供給程序員的糖衣,編譯時會對這些語法特殊處理。語法糖雖然不會帶來實(shí)質(zhì)性的改進(jìn),但是在提高代碼可讀性,提高語法嚴(yán)謹(jǐn)性,減少編碼錯誤機(jī)會上確實(shí)做出了很大貢獻(xiàn)。

Java要求集合必須實(shí)現(xiàn)Iterable接口,才能使用for-each語法糖遍歷該集合的實(shí)例。

JDK對該接口的描述是:Implementing this interface allows an object to be the target of * the "for-each loop" statement.

接口如下:public?interface?Iterable?{

Iterator?iterator();

default?void?forEach(Consumer?super?T>?action)?{

Objects.requireNonNull(action);????????for?(T?t?:?this)?{

action.accept(t);

}

}

default?Spliterator?spliterator()?{????????return?Spliterators.spliteratorUnknownSize(iterator(),?0);

}

}

忽略默認(rèn)方法,該接口要求集合實(shí)現(xiàn)iterator()方法,并返回一個迭代器對象Iterator。這也是java中的集合通過實(shí)現(xiàn)Iterable接口,組合Iterator來提供迭代器,并不通過直接實(shí)現(xiàn)Iterator接口的方式來提供集合迭代器的原因了。所有java集合迭代器的直接用法都如下:List?ls?=?new?ArrayList<>();

Iterator?it?=?ls.iterator();while?(it.hasNext())?{

System.out.println(it.next());

}

for-each的編譯器實(shí)現(xiàn)

for-each遍歷集合,實(shí)際上被翻譯如下:for?(I?#i?=?Expression.iterator();?#i.hasNext();?)?{

{VariableModifier}?TargetType?Identifier?=

(TargetType)?#i.next();

Statement

}

當(dāng)然,除了集合,for-each還可以遍歷數(shù)組,翻譯如下:T[]?#a?=?Expression;

L1:?L2:?...?Lm:for?(int?#i?=?0;?#i?

{VariableModifier}?TargetType?Identifier?=?#a[#i];

Statement

}

另外,使用javap命令,反編譯字節(jié)碼,可以看到編譯器是怎樣處理for-each的。public?class?Test?{????public?static?void?main(String[]?args)?{

List?ls?=?new?ArrayList<>();????????for?(String?s:?ls)?{

}

}

}

以上源文件對應(yīng)class文件的反編譯匯編為:C:\OTHERS\Working\ideaWork\utils\Z_practice\src\main\java>javap?-c?pattern\adapter\java_example\Test.class

Compiled?from?"Test.java"public?class?pattern.adapter.java_example.Test?{??public?pattern.adapter.java_example.Test();

Code:???????0:?aload_0???????1:?invokespecial?#1??????????????????//?Method?java/lang/Object."":()V

4:?return

public?static?void?main(java.lang.String[]);

Code:???????0:?new???????????#2??????????????????//?class?java/util/ArrayList

3:?dup???????4:?invokespecial?#3??????????????????//?Method?java/util/ArrayList."":()V

7:?astore_1???????8:?aload_1???????9:?invokeinterface?#4,??1????????????//?InterfaceMethod?java/util/List.iterator:()Ljava/util/Iterator;

14:?astore_2??????15:?aload_2??????16:?invokeinterface?#5,??1????????????//?InterfaceMethod?java/util/Iterator.hasNext:()Z

21:?ifeq??????????37

24:?aload_2??????25:?invokeinterface?#6,??1????????????//?InterfaceMethod?java/util/Iterator.next:()Ljava/lang/Object;

30:?checkcast?????#7??????????????????//?class?java/lang/String

33:?astore_3??????34:?goto??????????15

37:?return}

不用關(guān)注全部匯編細(xì)節(jié),只需要看到InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;就知道實(shí)際上是使用了迭代器。

至于數(shù)組的for-each,也可以通過觀察class文件的匯編代碼理解。

四、最佳實(shí)踐for-each遍歷的集合對象不能為null

既然對集合的for-each遍歷實(shí)際上是使用迭代器,會調(diào)用集合對象的iterator()方法獲得迭代器,那么,對null集合的for-each遍歷,就會在null集合對象上調(diào)用方法,勢必會拋出空指針異常。

for-each遍歷時不能改變正在遍歷的集合

因?yàn)樵谑褂玫鞅闅v集合時,不能夠改變集合,所以for-each遍歷時改變集合,同樣會引發(fā)ConcurrentModificationException異常。

作者:理查德成

鏈接:https://www.jianshu.com/p/186bf11ffe51

總結(jié)

以上是生活随笔為你收集整理的java for 迭代器_Java基础-迭代器Iterator与语法糖for-each的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。