系列中的上一篇
当前教程
集合元素的迭代
系列中的下一篇

系列中的上一篇: 在集合中存储元素

系列中的下一篇: 用 List 扩展集合

集合元素的迭代

 

使用 for-each 模式

迭代集合元素最简单的选择是使用 for-each 模式。

Collection<String> strings = List.of("one", "two", "three");

for (String element: strings) {
    System.out.println(element);
}

运行此代码会产生以下结果

one
two
three

只要您只需要读取集合的元素,这种模式就非常有效。 Iterator 模式允许在迭代集合时删除一些元素。如果您需要这样做,那么您需要使用 Iterator 模式。

 

在集合上使用迭代器

迭代集合的元素使用一个特殊对象,即 Iterator 接口的实例。您可以从 Collection 接口的任何扩展中获取 Iterator 对象。 iterator() 方法在 Iterable 接口上定义,由 Collection 接口扩展,并由集合层次结构中的所有接口进一步扩展。

使用此对象迭代集合元素是一个两步过程。

  1. 首先,您需要使用 hasNext() 方法检查是否有更多元素要访问
  2. 然后,您可以使用 next() 方法前进到下一个元素。

如果您调用 next() 方法,但集合中没有更多元素,您将获得一个 NoSuchElementException。调用 hasNext() 不是强制性的,它可以帮助您确保确实存在下一个元素。

以下是模式

Collection<String> strings = List.of("one", "two", "three", "four");
for (Iterator<String> iterator = strings.iterator(); iterator.hasNext();) {
    String element = iterator.next();
    if (element.length() == 3) {
        System.out.println(element);
    }
}

此代码会产生以下结果

one
two

Iterator 接口有第三个方法: remove()。调用此方法会从集合中删除当前元素。但是,在某些情况下,此方法不受支持,它将抛出一个 UnsupportedOperationException。很明显,在不可变集合上调用 remove() 无法工作,因此这是其中一种情况。您从 ArrayListLinkedListHashSet 获得的 Iterator 的实现都支持此删除操作。

 

在迭代集合时更新集合

如果您碰巧在迭代集合时修改了集合的内容,您可能会得到一个 ConcurrentModificationException。获得此异常可能有点令人困惑,因为此异常也用于并发编程。在集合框架的上下文中,您可能会在不接触多线程编程的情况下获得它。

以下代码会抛出一个 ConcurrentModificationException

Collection<String> strings = new ArrayList<>();
strings.add("one");
strings.add("two");
strings.add("three");

Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()) {

    String element = iterator.next();
    strings.remove(element);
}

如果您需要删除满足给定条件的集合元素,您可以使用 removeIf() 方法。

 

实现 Iterable 接口

现在您已经了解了集合框架中的迭代器,您可以创建 Iterable 接口的简单实现。

假设您需要创建一个 Range 类来模拟两个限制之间的整数范围。您需要做的就是从第一个整数迭代到最后一个整数。

您可以使用记录来实现 Iterable 接口,这是 Java SE 16 中引入的功能

record Range(int start, int end) implements Iterable<Integer> {

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            private int index = start;
            
            @Override
            public boolean hasNext() {
                return index < end;
            }

            @Override
            public Integer next() {
                if (index > end) {
                    throw new NoSuchElementException("" + index);
                }
                int currentIndex = index;
                index++;
                return currentIndex;
            }
        };
    }
}

如果您应用不支持 Java SE 16,则可以使用普通类执行相同的操作。请注意, Iterator 实现的代码完全相同。

class Range implements Iterable<Integer> {

    private final int start;
    private final int end;
    
    public Range(int start, int end) {
        this.start = start;
        this.end = end;
    }
    
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            private int index = start;
            
            @Override
            public boolean hasNext() {
                return index < end;
            }

            @Override
            public Integer next() {
                if (index > end) {
                    throw new NoSuchElementException("" + index);
                }
                int currentIndex = index;
                index++;
                return currentIndex;
            }
        };
    }
}

在这两种情况下,您都可以在 for-each 语句中使用 Range 的实例,因为它实现了 Iterable

for (int i : new Range1(0, 5)) {
    System.out.println("i = " + i);
}

运行此代码会产生以下结果

i = 0
i = 1
i = 2
i = 3
i = 4

上次更新: 2021 年 9 月 14 日


系列中的上一篇
当前教程
集合元素的迭代
系列中的下一篇

系列中的上一篇: 在集合中存储元素

系列中的下一篇: 用 List 扩展集合