Java迭代器原理

1迭代器模式

迭代器是一種設計模式,這種模式用于順序訪問集合對象的元素,不需要知道集合對象的底層表示。

一般實現方式如下:(來自)

?

public interface Iterator {public boolean hasNext();public Object next();
}
public interface Container {public Iterator getIterator();
}
public class NameRepository implements Container {public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};@Overridepublic Iterator getIterator() {return new NameIterator();}private class NameIterator implements Iterator {int index;@Overridepublic boolean hasNext() {if(index < names.length){return true;}return false;}@Overridepublic Object next() {if(this.hasNext()){return names[index++];}return null;}        }
}
public class IteratorPatternDemo {public static void main(String[] args) {NameRepository namesRepository = new NameRepository();for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){String name = (String)iter.next();System.out.println("Name : " + name);}     }
}

一般情況,我們自己開發時很少自定義迭代器,因為java本身已經把迭代器做到內部中了

2Java中的迭代器

(1)Iterator接口

package java.util;import java.util.function.Consumer;public interface Iterator<E> {/**
* 如果迭代器又更多的元素,返回true。* 換句話說,如果next方法返回一個元素而不是拋出一個異常,則返回true。
*/
boolean hasNext();//返回迭代器中的下一個元素,如果沒有,則拋出NoSuchElementException異常 E next();/**
* 從底層集合中刪除該迭代器返回的最后一個元素(可選操作)。每執行一次next方法這個方法只能被調用1次。* 如果在迭代過程中,除了調用此方法之外,任何其他方法修改基礎集合,則迭代器的行為是不確定的。 * 默認實現是拋出一個UnsupportedOperationException異常,不執行其他操作。 * 如果每次調用該方法前next方法沒有執行,則拋出IllegalStateException異常。
*/
default void remove() {throw new UnsupportedOperationException("remove");}/**
*
@since 1.8(函數編程)。 * 對每個剩余元素執行給定的操作,直到所有元素都被處理或動作拋出異常為止。 * 如果指定了該順序,則按迭代順序執行操作。動作拋出的異常被傳遞給調用者。 * 如果action為null,則拋出NullPointerException
*/
default void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);while (hasNext())action.accept(next());} }

?

首先,Iterator接口是屬于java.util包的。然后里面只有4個方法(用法介紹請看注釋)。

forEachRemaining方法是Java8函數編程新加入的。作用是對前游標之后的每個元素進行處理(沒有返回值),具體怎么處理根據傳入的函數。這項里操作使得迭代器更加靈活,操作粒度更加細致。

補充:default關鍵字可以讓接口中的方法可以有默認的函數體,當一個類實現這個接口時,可以不用去實現這個方法,當然,這個類若實現這個方法,就等于子類覆蓋了這個方法,最終運行結果符合Java多態特性。(Java8的新特性)

類注釋:

/*** An iterator over a collection.  {@code Iterator} takes the place of {@link Enumeration} in the Java Collections Framework.  Iterators* differ from enumerations in two ways:** <ul>*      <li> Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.*      <li> Method names have been improved.* </ul>** <p>This interface is a member of the <a href="{@docRoot}/../technotes/guides/collections/index.html">Java Collections Framework</a>.*/

Iterator是集合上的迭代器。在Java集合框架中Iterator用來替代Enumeration,Iterator與Enumeration有以下兩點區別:

  • Iterator允許調用者通過定于語義良好的迭代器刪除底層集合中的元素。
  • 方法名稱已得到改進。

這個接口是Java集合框架的成員。除了如上兩點不同外,Java8版本Iterator還加入了函數式編程。

(2)Iterable接口

package java.lang;// 實現此接口,允許對象成為“for-each loop”語句的目標。
public interface Iterable<T> {
// 返回類型為 T元素的迭代器。Iterator<T> iterator();/*** @since 1.8
* 對Iterable的每個元素執行給定的操作,直到所有元素都被處理或動作引發異常。
* 除非實現類另有規定,否則按照迭代的順序執行操作(如果指定了迭代順序)。 動作拋出的異常被轉發給調用者。
* 拋出NullPointerException - 如果指定的動作為空
*/default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}/*** @since 1.8
* 在Iterable描述的元素上創建一個Spliterator。Spliterator繼承了迭代器的fail-fast屬性。
*
*/default Spliterator<T> spliterator() {return Spliterators.spliteratorUnknownSize(iterator(), 0);} }

Java集合包最常用的有Collection和Map兩個接口的實現類。Map的實現類迭代器是內部實現的,而Collection繼承了Iterable接口。

這里以ArrayList為例,梳理一下Iterator的工作流程。

ArrayList是Collection的子類,而Collection又實現了Iterable接口,Iterable接口里面有iterator()方法(該方法返回一個迭代器對象)。所以,ArrayList(或其父類)也必須實現iterator()方法。

iterator()方法返回一個Iterator對象,而前文中Iterator是個接口。我們不能不知道具體用哪個實現類也不能直接new接口,所以我們找到其直接父類AbstractList,查看iterator()到底如何實現的:

?

 public Iterator<E> iterator() {return new Itr();}private class Itr implements Iterator<E> {// Index of element to be returned by subsequent call to next.int cursor = 0;/*** Index of element returned by most recent call to next or* previous.  Reset to -1 if this element is deleted by a call* to remove.*/int lastRet = -1;/*** The modCount value that the iterator believes that the backing* List should have.  If this expectation is violated, the iterator* has detected concurrent modification.*/int expectedModCount = modCount;public boolean hasNext() {return cursor != size();}public E next() {checkForComodification();try {int i = cursor;E next = get(i);lastRet = i;cursor = i + 1;return next;} catch (IndexOutOfBoundsException e) {checkForComodification();throw new NoSuchElementException();}}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {AbstractList.this.remove(lastRet);if (lastRet < cursor)cursor--;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException e) {throw new ConcurrentModificationException();}}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}

?

這里是通過內部類實現了Iterator接口,然后再將其實例對象返回。

?

原理很簡單,每調用一次next方法,先返回當前游標指向位置的值,然后游標往下移動一位,直到游標數值等于list的size。

而在ArrayList類里面又提供了一個實現版本:

    /*** An optimized version of AbstractList.Itr*/private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;Itr() {}public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")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];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}@Override@SuppressWarnings("unchecked")public void forEachRemaining(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i = cursor;if (i >= size) {return;}final Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) {throw new ConcurrentModificationException();}while (i != size && modCount == expectedModCount) {consumer.accept((E) elementData[i++]);}// update once at end of iteration to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}

next方法很好理解,和父類大概是一個意思。remove方法是調用ArrayList.this.remove(lastRet)實現:

?

public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue;}

?

numMoved 是計算要移動的元素個數(刪除數組的某一位置的值,后面的值要依次往前移)。

cursor = lastRet;

lastRet = -1;

表示刪除之后,游標前移1位。為什么這么做?舉個例子,數組a = [1,2,3,4],若cursor = 2,游標指向數字3,則lastRet = 1。當刪除a[1]的時候,a = [1,3,4]。3對應的位置變為1了,所以會有cursor = lastRet。

lastRet的值置為-1,這里很好的解釋了前面注釋中為什么remove方法一定要在next方法之后執行了。

?

轉載于:https://www.cnblogs.com/ouym/p/8857448.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/280575.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/280575.shtml
英文地址,請注明出處:http://en.pswp.cn/news/280575.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

企業版Java EE正式易主 甲骨文再次放手

有人說甲骨文收購的東西大多沒有了好下場&#xff0c;這么說雖然有些片面&#xff0c;但是最近一個月Java EE和Solaris的境遇難免讓人產生類似的聯想。 繼筆者上次報道《甲骨文將放棄Java EE 開源基金會雙手歡迎》之后&#xff0c;最新消息顯示&#xff0c;原本在甲骨文手中的J…

js中各種位置

js中各種位置 js中有各種與位置相關的屬性,每次看到的時候都各種懵逼。索性一次總結一下。 clientHeight 內容可視區域的高度。包括padding不包括border、水平滾動條、margin。對于inline的元素這個屬性一直是0&#xff0c;單位px&#xff0c;只讀元素。offsetHeight offsetHei…

如何判斷您是否擁有32位或64位版本的Google Chrome瀏覽器

Google Chrome is extremely popular with our readers, but did you know that they also have a 64-bit version of the browser these days? Here’s how to tell which version you are running, and how to switch if you aren’t. 谷歌瀏覽器在我們的讀者中非常受歡迎&a…

django14:CBV加入裝飾器

加在方法上面 from django.utils.decorators import method_decoratorclass HomeView(View):def dispatch(self, request, *args, **kwargs):return super(HomeView, self).dispatch(request, *args, **kwargs)def get(self, request):return render(request, "home.html&…

Kubernetes 跨集群流量調度實戰 :訪問控制

背景眾所周知&#xff0c;Flomesh 的服務網格產品 osm-edge[1] 是基于 SMI&#xff08;Service Mesh Interface&#xff0c;服務網格接口&#xff09; 標準的實現。SMI 定義了流量標識、訪問控制、遙測和管理的規范。在 上一篇 中&#xff0c;我們體驗過了多集群服務&#xff0…

python下sqlite增刪查改方法(轉)

sqlite讀寫 #codingutf-8 import sqlite3 import os #創建數據庫和游標 if os.path.exists( test.db):connsqlite3.connect( test.db)curconn.cursor() else:connsqlite3.connect( test.db)curconn.cursor()#創建表 cur.execute(CREATE TABLE IF NOT EXISTS customer (ID VARCH…

Apache HTTP Server 與 Tomcat 的三種連接方式介紹

本文轉載自IBM developer 首先我們先介紹一下為什么要讓 Apache 與 Tomcat 之間進行連接。事實上 Tomcat 本身已經提供了 HTTP 服務&#xff0c;該服務默認的端口是 8080&#xff0c;裝好 tomcat 后通過 8080 端口可以直接使用 Tomcat 所運行的應用程序&#xff0c;你也可以將該…

印象筆記和有道云筆記程序員_記錄,存儲和共享筆記的最佳應用程序和云服務...

印象筆記和有道云筆記程序員Is your desk and computer covered with sticky notes? Do you have miscellaneous pieces of paper with bits of information buried in drawers, your laptop case, backpack, purse, etc.? Get rid of all the chaos and get organized with …

java B2B2C 仿淘寶電子商城系統-Spring Cloud Eureka參數配置項詳解

Eureka涉及到的參數配置項數量眾多&#xff0c;它的很多功能都是通過參數配置來實現的&#xff0c;了解這些參數的含義有助于我們更好的應用Eureka的各種功能&#xff0c;下面對Eureka的配置項做具體介紹&#xff0c;供大家參考。 需要JAVA Spring Cloud大型企業分布式微服務云…

django15:中間件

中間件 開發django項目是&#xff0c;涉及全局相關功能&#xff0c;都可以使用中間件實現。 1.請求時&#xff0c;需要經過中間件&#xff0c;才能到達真正的django后端。 2.響應走的時候&#xff0c;也要經過中間件&#xff0c;才能出去。 依次經過里面的中間件進出&#x…

互聯網算法和產品優化的幾個反直覺現象

本文不涉及任何具體的業務和形態&#xff0c;沒有公開任何數據和需要保護的技術。互聯網產品和算法的優化&#xff0c;是廣大程序員和產品經理的主要工作。但想準確衡量線上實驗效果&#xff0c;從來都不簡單。筆者將這些反直覺現象&#xff0c;總結成三個典型案例予以討論。然…

SD 胡策 Round 1 T3 彩尾巴猹的二進制數

發現一個區間[L,R]代表的2進制數是3的倍數&#xff0c;當且僅當從L開始的后綴二進制值 - 從R1開始的后綴二進制值 是 3 的倍數 (具體證明因為太簡單而被屏蔽)。 于是我們就可以在每個點維護從它開始的后綴二進制數的值&#xff0c;因為在%3同余系下只有3個數&#xff0c;所以我…

求解10的75次方問題

對于求一個數的高次方&#xff0c;最簡單的方法&#xff0c;恐怕就是循環一定的次數&#xff0c;累乘。但是這樣的效率太低。下面我提供一個高效的算法。來自左程云《程序員代碼面試指南》。 就拿10的75次方舉例&#xff1a; 1.75的二進制數形式是1001011。 2.10的75次方10的64…

又是新的一周

自己的決定還記得嗎轉載于:https://www.cnblogs.com/zhangxiangning/p/10300093.html

django16: csrf跨站請求偽造/CSRF相關裝飾器

CSRF 即跨站請求攻擊 跨站請求偽造csrf釣魚網站本質搭建一個跟正常網站一模一樣的頁面用戶在該頁面上完成轉賬功能轉賬的請求確實是朝著正常網站的服務端提交唯一不同的在于收款賬戶人不同給用戶書寫form表單 對方賬戶的input沒有name屬性你自己悄悄提前寫好了一個具有默認的…

dropbox_Google的新存儲定價與Microsoft,Apple和Dropbox相比如何

dropboxGoogle’s subscription storage service has a new name: Google One. Some prices are dropping and customers will also get customer support from an actual human for the first time. Google的訂閱存儲服務有一個新名稱&#xff1a;Google One。 一些價格正在下…

WPF效果第二百零六篇之快速黑白灰效果

一大早就看到群友討論怎么快速讓界面黑白灰效果,這不突然想起來N年前咱簡單通過ShaderEffects調節過飽和度、對比度、亮度;今天再次玩耍一下;來看看最終實現的效果:1、核心代碼&#xff1a;sampler2D implicitInput : register(s0); float factor : register(c0); float4 main(…

極大似然估計與貝葉斯定理

文章轉載自&#xff1a;https://blog.csdn.net/zengxiantao1994/article/details/72787849 極大似然估計-形象解釋看這篇文章&#xff1a;https://www.zhihu.com/question/24124998 貝葉斯定理-形象解釋看這篇文章&#xff1a;https://www.zhihu.com/question/19725590/answer/…

艾媒:第三方應用商店形成BAT3爭霸格局

iiMedia Research(艾媒咨詢)近日發布的《2016Q2中國移動應用商店市場監測報告》&#xff0c;報告顯示&#xff0c;2016年第二季度&#xff0c;第三方移動應用商店用戶增長放緩&#xff0c;用戶規模逐漸飽和。同時&#xff0c;隨著豌豆莢宣布并入阿里移動事業群&#xff0c;中國…

編譯安裝內核

編譯安裝內核 升級內核到 linux-4.20.3.tar.xz 查看當前內核版本&#xff1a; [rootcentos7 data]#uname -r 3.10.0-862.el7.x86_64獲取內核源代碼包&#xff1a;www.kernel.org linux-4.20.3.tar.xz 實施步驟 1. 安裝編譯所需的工具 gcc ncurses-devel make&#xff08;開發工…