您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java中如何使用Iterator和Iterable接口”,在日常操作中,相信很多人在Java中如何使用Iterator和Iterable接口問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java中如何使用Iterator和Iterable接口”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
當我們使用 for
或 while
循環來遍歷一個集合的元素,Iterator
允許我們不用擔心索引位置,甚至讓我們不僅僅是遍歷一個集合,同時還可以改變它。例如,你如果要刪除循環中的元素,那么 for
循環不見得總是可行的。
結合自定義的迭代器,我們可以迭代更為復雜的對象,以及向前和向后移動,并且知曉如何利用其優勢也將變得非常清楚。
Iterator
接口用于迭代集合中的元素(List
,Set
或 Map
)。它用于逐個檢索元素,并在需要時針對每個元素執行操作。
下面是用于遍歷集合與執行操作的方法:
.hasNext()
:如果還沒有到達集合的末尾,則返回 true
,否則返回 false
.next()
:返回集合中的下一個元素
.remove()
:從集合中移除迭代器返回的最后一個元素
.forEachRemaining()
:按順序為集合中剩下的每個元素執行給定的操作
首先,由于迭代器是用于集合的,讓我們做一個簡單的包含幾個元素的 ArrayList
:
List<string> avengers = new ArrayList<>(); // Now lets add some Avengers to the list avengers.add("Ant-Man"); avengers.add("Black Widow"); avengers.add("Captain America"); avengers.add("Doctor Strange");
我們可以使用一個簡單循環來遍歷這個集合:
System.out.println("Simple loop example:\n"); for (int i = 0; i < avengers.size(); i++) { System.out.println(avengers.get(i)); }
不過,我們想探索迭代器:
System.out.println("\nIterator Example:\n"); // First we make an Iterator by calling // the .iterator() method on the collection Iterator<string> avengersIterator = avengers.iterator(); // And now we use .hasNext() and .next() to go through it while (avengersIterator.hasNext()) { System.out.println(avengersIterator.next()); }
如果我們想從這個 ArrayList
中刪除一個元素,會發生什么?讓我們試著使用常規的 for
循環:
System.out.println("Simple loop example:\n"); for (int i = 0; i < avengers.size(); i++) { if (avengers.get(i).equals("Doctor Strange")) { avengers.remove(i); } System.out.println(avengers.get(i)); }
我們會收到一個討厭的 IndexOutOfBoundsException
:
Simple loop example: Ant-Man Black Widow Captain America Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
這在遍歷集合時更改其大小是有意義的,增強 for
循環也一樣:
System.out.println("Simple loop example:\n"); for (String avenger : avengers) { if (avenger.equals("Doctor Strange")) { avengers.remove(avenger); } System.out.println(avenger); }
我們再次收到了另一個異常:
Simple loop example: Ant-Man Black Widow Captain America Doctor Strange Exception in thread "main" java.util.ConcurrentModificationException
這時迭代器就派上用場了,由它充當中間人,從集合中刪除元素,同時確保遍歷按計劃繼續:
Iterator<string> avengersIterator = avengers.iterator(); while (avengersIterator.hasNext()) { String avenger = avengersIterator.next(); // First we must find the element we wish to remove if (avenger.equals("Ant-Man")) { // This will remove "Ant-Man" from the original // collection, in this case a List avengersIterator.remove(); } }
這是保證在遍歷集合時刪除元素的安全方法。
并確認該元素是否已被刪除:
// We can also use the helper method .forEachRemaining() System.out.println("For Each Remaining Example:\n"); Iterator<string> avengersIteratorForEach = avengers.iterator(); // This will apply System.out::println to all elements in the collection avengersIteratorForEach.forEachRemaining(System.out::println);
輸出如下:
For Each Remaining Example: Black Widow Captain America Doctor Strange
正如你所看到的,蟻人已經從 復仇者聯盟
的名單中刪除了。
ListIterator
繼承自 Iterator
接口。它只在 List
上進行使用,可以雙向迭代,這意味著你可以從前到后或從后到前進行迭代。它也沒有 current 元素,因為游標總是放在 List
的兩個元素之間,所以我們用 .previous()
或 .next()
來訪問元素。
> Iterator
和 ListIterator
之間有什么區別呢?
首先,Iterator
可以用于 任意集合 —— List
、Map
、Queue
、Set
等。
ListIterator
只能應用于 List,通過添加這個限制,ListIterator
在方法方面可以更加具體,因此,我們引入了許多新方法,他們可以幫助我們在遍歷時對其進行修改。
如果你正在處理 List
實現(ArrayList
、LinkedList
等),那么使用 ListIterator
更為可取一些。
下面是你可能會用到的方法:
.add(E e)
:向 List 中添加元素。
.remove()
:從 List 中刪除 .next()
或 .previous()
返回的最后一個元素。
.set(E e)
:使用指定元素來覆蓋 List .next()
或 .previous()
返回的最后一個元素。
.hasNext()
:如果還沒有到達 List 的末尾,則返回 true
,否則返回 false
。
.next()
:返回 List 中的下一個元素。
.nextIndex()
:返回下一元素的下標。
.hasPrevious()
:如果還沒有到達 List 的開頭,則返回 true
,否則返回 false
。
.previous()
:返回 List 的上一個元素。
.previousIndex()
:返回上一元素的下標。
再次,讓我們用一些元素構成一個 ArrayList
:
ArrayList<string> defenders = new ArrayList<>(); defenders.add("Daredevil"); defenders.add("Luke Cage"); defenders.add("Jessica Jones"); defenders.add("Iron Fist");
讓我們用 ListIterator
來遍歷 List 并打印其元素:
ListIterator listIterator = defenders.listIterator(); System.out.println("Original contents of our List:\n"); while (listIterator.hasNext()) System.out.print(listIterator.next() + System.lineSeparator());
顯然,它的工作方式與 Iterator
相同。輸出如下:
Original contents of our List: Daredevil Luke Cage Jessica Jones Iron Fist
現在,讓我們來嘗試修改一些元素:
System.out.println("Modified contents of our List:\n"); // Now let's make a ListIterator and modify the elements ListIterator defendersListIterator = defenders.listIterator(); while (defendersListIterator.hasNext()) { Object element = defendersListIterator.next(); defendersListIterator.set("The Mighty Defender: " + element); }
現在打印 List 的話會得到如下結果:
Modified contents of our List: The Mighty Defender: Daredevil The Mighty Defender: Luke Cage The Mighty Defender: Jessica Jones The Mighty Defender: Iron Fist
現在,讓我們倒著遍歷列表,就像我們可以用 ListIterator
做的那樣:
System.out.println("Modified List backwards:\n"); while (defendersListIterator.hasPrevious()) { System.out.println(defendersListIterator.previous()); }
輸出如下:
Modified List backwards: The Mighty Defender: Iron Fist The Mighty Defender: Jessica Jones The Mighty Defender: Luke Cage The Mighty Defender: Daredevil
Spliterator
接口在功能上與 Iterator
相同。你可能永遠不需要直接使用 Spliterator
,但讓我們繼續討論一些用例。
但是,你應首先熟悉 Java Streams 和 Lambda Expressions in Java。
雖然我們將列出 Spliterator
擁有的所有方法,但是 Spliterator
接口的全部工作超出了本文的范疇。我們將通過一個例子討論 Spliterator
如何使用并行化更有效地遍歷我們可以分解的 Stream
。
我們在處理 Spliterator
時使用的方法是:
.characteristics()
: 返回該 Spliterator 具有的作為
int
值的特征。 這些包括:
ORDERED
DISTINCT
SORTED
SIZED
CONCURRENT
IMMUTABLE
NONNULL
SUBSIZED
.estimateSize()
:返回遍歷作為 long
值遇到的元素數量的估計值,如果無法返回則返回 long.MAX_VALUE
。
.forEachRemaining(E e)
:按順序對集合中的每個剩余元素執行給定操作。
.getComparator()
:如果該 Spliterator
的源是由 Comparator
排序的,其將返回 Comparator
。
.getExactSizeIfKnown()
:如果大小已知則返回 .estimateSize()
,否則返回 -1
。
.hasCharacteristics(int characteristics)
:如果這個 Spliterator
的 .characteristics()
包含所有給定的特征,則返回 true
。
.tryAdvance(E e)
:如果存在剩余元素,則對其執行給定操作,返回 true
,否則返回 false
。
.trySplit()
:如果這個 Spliterator
可以被分區,返回一個 Spliterator
覆蓋元素,當從這個方法返回時,它將不被這個 Spliterator
覆蓋。
像往常一樣,讓我們從一個簡單的 ArrayList
開始:
List<string> mutants = new ArrayList<>(); mutants.add("Professor X"); mutants.add("Magneto"); mutants.add("Storm"); mutants.add("Jean Grey"); mutants.add("Wolverine"); mutants.add("Mystique");
現在,我們需要將 Spliterator
應用于 Stream
。值得慶幸的是,由于 Collections 框架,很容易在 ArrayList
和 Stream
之間進行轉換:
// Obtain a Stream to the mutants List. Stream<string> mutantStream = mutants.stream(); // Getting Spliterator object on mutantStream. Spliterator<string> mutantList = mutantStream.spliterator();
為了展示其中的一些方法,讓我們分別運行下它們:
// .estimateSize() method System.out.println("Estimate size: " + mutantList.estimateSize()); // .getExactSizeIfKnown() method System.out.println("\nExact size: " + mutantList.getExactSizeIfKnown()); System.out.println("\nContent of List:"); // .forEachRemaining() method mutantList.forEachRemaining((n) -> System.out.println(n)); // Obtaining another Stream to the mutant List. Spliterator<string> splitList1 = mutantStream.spliterator(); // .trySplit() method Spliterator<string> splitList2 = splitList1.trySplit(); // If splitList1 could be split, use splitList2 first. if (splitList2 != null) { System.out.println("\nOutput from splitList2:"); splitList2.forEachRemaining((n) -> System.out.println(n)); } // Now, use the splitList1 System.out.println("\nOutput from splitList1:"); splitList1.forEachRemaining((n) -> System.out.println(n));
我們將得到輸出:
Estimate size: 6 Exact size: 6 Content of List: Professor X Magneto Storm Jean Grey Wolverine Mystique Output from splitList2: Professor X Magneto Storm Output from splitList1: Jean Grey Wolverine Mystique
如果出于某種原因,我們想要創建一個自定義的 Iterator
接口,應該怎么辦?你首先要熟悉的是這張圖:
要創建自定義 Iterator
,我們需要為 .hasNext()
、.next()
和 .remove()
做自定義實現。
在 Iterator
接口中,有一個方法,它返回一個集合中元素的迭代器,即 .iterator()
方法,還有一個方法為迭代器中的每個元素執行一個操作的方法,即 .dorEach()
方法。
例如,假設我們是 Tony Stark,我們需要寫個自定義迭代器來列出當前武器庫中的每件鋼鐵俠套裝。
首先,讓我們創建一個類來獲取和設置 suit 數據:
public class Suit { private String codename; private int mark; public Suit(String codename, int mark) { this.codename = codename; this.mark = mark; } public String getCodename() { return codename; } public int getMark() { return mark; } public void setCodename (String codename) {this.codename=codename;} public void setMark (int mark) {this.mark=mark;} public String toString() { return "mark: " + mark + ", codename: " + codename; } }
接下來讓我們編寫自定義 Iterator:
// Our custom Iterator must implement the Iterable interface public class Armoury implements Iterable<suit> { // Notice that we are using our own class as a data type private List<suit> list = null; public Armoury() { // Fill the List with data list = new LinkedList<suit>(); list.add(new Suit("HOTROD", 22)); list.add(new Suit("SILVER CENTURION", 33)); list.add(new Suit("SOUTHPAW", 34)); list.add(new Suit("HULKBUSTER 2.0", 48)); } public Iterator<suit> iterator() { return new CustomIterator<suit>(list); } // Here we are writing our custom Iterator // Notice the generic class E since we do not need to specify an exact class public class CustomIterator<e> implements Iterator<e> { // We need an index to know if we have reached the end of the collection int indexPosition = 0; // We will iterate through the collection as a List List<e> internalList; public CustomIterator(List<e> internalList) { this.internalList = internalList; } // Since java indexes elements from 0, we need to check against indexPosition +1 // to see if we have reached the end of the collection public boolean hasNext() { if (internalList.size() >= indexPosition +1) { return true; } return false; } // This is our custom .next() method public E next() { E val = internalList.get(indexPosition); // If for example, we were to put here "indexPosition +=2" we would skip every // second element in a collection. This is a simple example but we could // write very complex code here to filter precisely which elements are // returned. // Something which would be much more tedious to do with a for or while loop indexPosition += 1; return val; } // In this example we do not need a .remove() method, but it can also be // written if required } }
最后是 main 方法類:
public class IronMan { public static void main(String[] args) { Armoury armoury = new Armoury(); // Instead of manually writing .hasNext() and .next() methods to iterate through // our collection we can simply use the advanced forloop for (Suit s : armoury) { System.out.println(s); } } }
輸出如下:
mark: 22, codename: HOTROD mark: 33, codename: SILVER CENTURION mark: 34, codename: SOUTHPAW mark: 48, codename: HULKBUSTER 2.0
到此,關于“Java中如何使用Iterator和Iterable接口”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。