今天我们将讨论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