# Java 外部与内部迭代器

原文：http://zetcode.com/java/externalinternaliterator/

Java 外部和内部迭代器展示了 Java 中外部和内部迭代器之间的区别。

迭代器是使程序员能够遍历列表和映射之类的容器的对象。

## 迭代器类型

迭代器有两种类型：外部和内部。 外部迭代器是主动的，内部迭代器是被动的。

当客户端（即程序员）控制迭代时，该迭代器称为外部迭代器。 当迭代器控制它时，它称为内部迭代器。

通常，建议使用内部迭代器而不是外部迭代器。 内部迭代不易出错，更易读，并且需要更少的代码。 另一方面，外部迭代器有时更灵活。 例如，在循环中对两个集合进行操作时。

## Java 外部迭代器示例

以下示例显示了外部迭代器的用法。

`JavaExternalIterationEx.java`

```java
package com.zetcode;

import java.util.List;

public class JavaExternalIterationEx {

    public static void main(String[] args) {

        List<String> words = List.of("hello", "sky", "there", "den", "sky");

        for (String word: words) {

            System.out.printf("The word %s has %d characters%n",
                    word, word.length());
        }
    }
}

```

在示例中，我们使用外部迭代器遍历单词列表，并以字符形式显示其元素及其大小。

```java
The word hello has 5 characters
The word sky has 3 characters
The word there has 5 characters
The word den has 3 characters
The word sky has 3 characters

```

这是输出。

### `ConcurrentModificationException`

当我们使用带有增强型`for`循环的外部迭代并修改集合的元素时，我们可能会收到`ConcurrentModificationException`。

`JavaExternalIterationEx2.java`

```java
package com.zetcode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class JavaExternalIterationEx2 {

    public static void main(String[] args) {

        List<String> words = new ArrayList<>(Arrays.asList("pen", "pencil",
                "sky", "blue", "sky", "dog"));

        for (String word: words) {

            if ("sky".equals(word)) {

                words.remove(word);
            }
        }

        System.out.println(words);
    }
}

```

在该示例中，我们要从列表中删除所有等于`"sky"`的单词。 这是出于演示目的； 从 Java8 开始，我们可以轻松地使用`removeIf()`方法删除元素：`words.removeIf(e -> "sky".equals(e));`

```java
Exception in thread "main" java.util.ConcurrentModificationException

```

运行示例将导致`ConcurrentModificationException`。

Java 工作中其他形式的外部迭代。

```java
Iterator<String> iter = words.iterator();

while (iter.hasNext()) {
    String s = iter.next();

    if ("sky".equals(s)) {
        iter.remove();
    }
}

```

该示例可以在带有`while`循环的老式迭代中正常运行。

```java
for (int i=words.size() - 1; i>=0; i--) {

    if ("sky".equals(words.get(i))) {
        words.remove(i);
    }
}

```

它也可以与传统的`for`循环一起使用。

还要注意，在这种情况下，为每个循环使用并不会导致所有语言的错误。 例如，Python 3 或 Perl 6 可以正常工作。 另一方面，JavaScript 和 C++ 也会出错。

`extit.py`

```java
#!/usr/bin/python3

words = ["pen", "pencil", "dog", "sky", "blue", "sky"]

print(len(words))

for word in words:
    if word == "sky":
        words.remove(word)

print(words)
print(len(words))

```

这是 Python 3 中的等效代码。可以正常工作。

## Java 内部迭代器示例

在以下示例中，我们使用内部迭代器。

`JavaInternalIteratorEx.java`

```java
package com.zetcode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class JavaInternalIteratorEx {

    public static void main(String[] args) {

        List<String> words = List.of("hello", "sky", "there", "den", "sky");

        words.stream().forEach(e -> 
                System.out.printf("The word %s has %d characters %n", e, e.length()));
    }
}

```

该示例遍历列表的所有元素，并打印它们及其大小。

`JavaInternalIteratorEx2.java`

```java
package com.zetcode;

import java.util.List;
import java.util.stream.Collectors;

public class JavaInternalIteratorEx2 {

    public static void main(String[] args) {

        List<String> words = List.of("hello", "sky", "there", "den", "sky");

        List<String> words2 = words.stream().filter(e -> !"sky".equals(e))
                                    .collect(Collectors.toList());

        System.out.println(words2);
    }
}

```

使用现代函数式 Java，我们展示了如何创建一个不包含`"sky"`一词的新不可变列表。

```java
[hello, there, den]

```

这是输出。

在本教程中，我们讨论了 Java 的内部和外部迭代器。 您可能也对相关教程感兴趣： [Java 复制文件](/java/copyfile/)， [Java 创建目录](/java/createdirectory/)， [Java 文件大小](/java/filesize/)，[用 Java 创建文件](/java/createfile/) ，[用 Java 读取文本文件](/articles/javareadtext/)， [Apache FileUtils 教程](/java/fileutils/)， [Java Swing 教程](/tutorials/javaswingtutorial/)和 [Java 教程](/lang/java/)。