今天我們將討論Java 中的 Iterator 是什麼以及為什麼需要它。
您可能已經知道,Java 有一個出色的 Collection 接口,它實作了 Iterator 接口。讓我立即保留意見:迭代器介面不應該與Java中的迭代器模式混淆!為了澄清這一點,我們先來看看介面。
讓我們想像一下 Java 中沒有迭代器。在這種情況下,每個人都必須深入集合的最深處,真正理解什麼是
從字面上看,“迭代器”可以翻譯為“蠻力” 。也就是說,它是某個實體,可以迭代集合中的所有元素。此外,它允許您無需深入研究集合的內部結構和排列即可做到這一點。 |
ArrayList
與LinkedList
什麼HashSet
不同TreeSet
。
Iterator必須實作的方法
boolean hasNext()
— 如果可迭代物件(目前是 Collection)中仍然有值,則該方法將傳回true
(如果沒有更多值)false
。 E next()
— 傳回集合(物件)的下一個元素。如果沒有更多元素(沒有 check ,我們在到達集合末尾時hasNext()
調用),則該方法將拋出。 - 將刪除最後獲得的元素。該方法可以拋出: next()
NoSuchElementException
void remove()
next()
UnsupportedOperationException
,如果此迭代器不支援該方法remove()
(例如,在只讀集合的情況下)IllegalStateException
,如果該方法next()
尚未被調用,或remove()
自上次調用以來已被調用next()
。
for-each
。它的擴充是ListIterator。讓我們看看其他的 java 列表迭代器方法。您很可能認識他們:
void add(E e)
— 插入一個元素E
到;List
boolean hasPrevious()
true
— 反向查找時如果List
有元素則回傳;int nextIndex()
— 將會傳回下一個元素的索引;E previous()
— 將傳回前一個工作表元素;int previousIndex()
— 將會傳回前一個元素的索引;void set(E e)
- 將取代上次呼叫傳回的元素next()
或previous()
的元素e
。
List
包含對學生的問候語的行:
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
現在我們將獲得它的迭代器並將所有包含的行列印到控制台:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
現在就會出現一個「瓶頸」:Java Collections,正如您可能知道的那樣(如果您不知道,請弄清楚),擴展接口,Iterable
但這並不意味著僅支援迭代器。For也受支持,但必須呼叫 for : List
Set
Queue
java Map iterator
Map.entrySet()
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
然後該方法next()
將傳回一個Entry
包含“鍵”-“值”對的物件。那麼一切都與以下相同List
:
while (mapIterator.hasNext()) {
Map.Entry<String, Integer> entry = mapIterator.next();
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
}
你想:「停下來。我們正在談論介面,文章的標題說「模式」。也就是說,迭代器模式就是Iterator介面?或者介面是一種模式嗎?如果這個字第一次出現,我給你一個參考:模式是一種設計模式,是一個類別或許多互連的類別必須遵守的某種行為。java中的迭代器可以為任何內部結構涉及迭代的物件實現,並且您可以更改正在討論的方法的簽章。實現模式時最重要的是類別必須遵守的邏輯。 迭代器介面是同名模式的私有實現,List, Set, Queue, Map
由程式設計師自行決定應用於現成的結構 ( ) 和其他結構。透過擴展 Iterator 接口,您可以實現一個模式,但不需要擴展該接口來實現該模式。一個簡單的比喻:所有的魚都會游泳,但不是所有會游泳的都是魚。作為一個例子,我決定採用……這個字。更具體地說,是一個名詞。它由幾個部分組成:前綴、詞根、後綴和詞尾。對於單字的一部分,我們將建立一個介面WordPart
和擴展它的類別Prefix, Root, Suffix и Ending
::
interface WordPart {
String getWordPart();
}
static class Root implements WordPart {
private String part;
public Root(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Prefix implements WordPart {
private String part;
public Prefix(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Suffix implements WordPart {
private String part;
public Suffix(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Ending implements WordPart {
private String part;
public Ending(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
然後類別Word
(單字)將包含部分,除了它們之外,我們還將添加一個反映單字中部分數量的整數:
public class Word {
private Root root;
private Prefix prefix;
private Suffix suffix;
private Ending ending;
private int partCount;
public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
this.root = root;
this.prefix = prefix;
this.suffix = suffix;
this.ending = ending;
this.partCount = 4;
}
public Word(Root root, Prefix prefix, Suffix suffix) {
this.root = root;
this.prefix = prefix;
this.suffix = suffix;
this.partCount = 3;
}
public Word(Root root, Prefix prefix) {
this.root = root;
this.prefix = prefix;
this.partCount = 2;
}
public Word(Root root) {
this.root = root;
this.partCount = 1;
}
public Root getRoot() {
return root;
}
public Prefix getPrefix() {
return prefix;
}
public Suffix getSuffix() {
return suffix;
}
public Ending getEnding() {
return ending;
}
public int getPartCount() {
return partCount;
}
public boolean hasRoot() {
return this.root != null;
}
public boolean hasPrefix() {
return this.prefix != null;
}
public boolean hasSuffix() {
return this.suffix != null;
}
public boolean hasEnding() {
return this.ending != null;
}
好的,我們有四個重載的建構子(為簡單起見,我們假設我們只能有一個後綴)。名詞不能由一個前綴組成,因此對於具有一個參數的建構函數,我們將設定根。現在讓我們來寫一個迭代器模式的實作:WordIterator,重寫 2 個方法:hasNext()
和next()
:
public class WordIterator implements Iterator<Word.WordPart> {
private Word word;
private int wordPartsCount;
public WordIterator(Word word) {
this.word = word;
this.wordPartsCount = word.getPartCount();
}
@Override
public boolean hasNext() {
if (wordPartsCount == 4) {
return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
} else if (wordPartsCount == 3) {
return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
} else if (wordPartsCount == 2) {
return word.hasPrefix() || word.hasRoot();
} else if (wordPartsCount == 1) {
return word.hasRoot();
}
return false;
}
@Override
public Word.WordPart next() throws NoSuchElementException {
if (wordPartsCount <= 0) {
throw new NoSuchElementException("No more elements in this word!");
}
try {
if (wordPartsCount == 4) {
return word.getEnding();
}
if (wordPartsCount == 3) {
return word.getSuffix();
}
if (wordPartsCount == 2) {
return word.getPrefix();
}
return word.getRoot();
} finally {
wordPartsCount--;
}
}
}
剩下的就是將迭代器分配給類別Word
:
public class Word implements Iterable<Word.WordPart> {
…
@Override
public Iterator<WordPart>iterator() {
return new WordIterator(this);
}
…
}
現在我們對「rush」一詞進行語素分析:
public class Main {
public static void main(String[] args) {
Word.Root root = new Word.Root("беж");
Word.Prefix prefix = new Word.Prefix("пере");
Word.Suffix suffix = new Word.Suffix("к");
Word.Ending ending = new Word.Ending("a");
Word word = new Word(root, prefix, suffix, ending);
Iterator wordIterator = word.iterator();
while (wordIterator.hasNext()) {
Word.WordPart part = (Word.WordPart) wordIterator.next();
System.out.println(part.getClass() + ": " + part.getWordPart());
}
}
}
請注意,在迭代器模式的實作中,我選擇了以下輸出順序:
- 結尾
- 後綴
- 安慰
- 根
GO TO FULL VERSION