Detect the Last Iteration in for Loops in Java – 检测 Java for 循环中的最后一次迭代

最后修改: 2023年 12月 18日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The for-each loop is an elegant and simple tool when we iterate over a List. Sometimes, there are scenarios where we need to perform specific actions or make decisions based on whether an iteration is the last one.

当我们迭代 List 时,for-each 循环是一个优雅而简单的工具。有时,我们需要根据迭代是否是最后一次来执行特定操作或做出决策。

In this tutorial, we’ll discuss this scenario and explore different ways to determine if the current iteration is the last one when we loop a List.

在本教程中,我们将讨论这种情况,并探索在循环 List. 时确定当前迭代是否为最后一次迭代的不同方法。

2. Introduction to the Problem

2.问题介绍

First, let’s create a List of movie titles as our input example:

首先,让我们创建一个电影标题 List 作为输入示例:

List<String> MOVIES = List.of(
  "Titanic",
  "The Deer Hunter",
  "Lord of the Rings",
  "One Flew Over the Cuckoo's Nest",
  "No Country For Old Men");

If we merely want to obtain the last element after a typical for-each loop, it isn’t a challenge. We can simply reassign the same variable with the element in each iteration. After we walk through the entire list, the variable holds the last element:

如果我们只是想在一个典型的 for-each 循环后获得最后一个元素,这并不是一个难题。我们只需在每次迭代中将元素重新分配给同一个变量即可。当我们走完整个列表后,变量就会保存最后一个元素:

String myLastMovie = "";
for (String movie : MOVIES) {
    // do some work with movie
    myLastMovie = movie;
}
assertEquals("No Country For Old Men", myLastMovie);

However, sometimes, we need to perform some particular actions only in the last iteration. So, during the looping, we must identify the last iteration within a for-each loop.

但有时,我们需要仅在最后一次迭代中执行某些特定操作。因此,在循环过程中,我们必须确定 for-each 循环中的最后一次迭代。

Unlike traditional for loops, where an index variable readily indicates the current iteration, the for-each loop conceals this information. Therefore, the absence of an explicit loop index poses a challenge to determine the last iteration.

在传统的 for 循环中,索引变量很容易显示当前迭代,而 for-each循环则不同,它隐藏了这一信息。因此,没有明确的循环索引会给确定最后一次迭代带来挑战。

Next, let’s see how to solve this problem.

接下来,让我们看看如何解决这个问题。

3. Using IntStream

3.使用 IntStream

We know that solving the problem using a traditional for loop isn’t difficult since we know the index of the current iteration:

我们知道,使用传统的 for 循环解决问题并不困难,因为我们知道当前迭代的索引:

int size = MOVIES.size();
String myLastMovie = null;
for (int i = 0; i < size; i++) {
    String movie = MOVIES.get(i)
    // ... work with movie
    if (i == size - 1) {
        myLastMovie = movie;
    }
}
assertEquals("No Country For Old Men", myLastMovie);

We can follow the same idea and create an IntStream containing all indexes of the list elements. Then, we can use the forEach() method to loop through the indexes and check whether the current is the last iteration, the same as in a traditional for loop:

我们可以遵循相同的思路,创建一个 IntStream 包含列表元素的所有索引。然后,我们可以使用 forEach() 方法在索引中循环,并检查当前是否是最后一次迭代,这与传统的 for 循环相同:

int size = MOVIES.size();
Map<Integer, String> myLastMovie = new HashMap<>();
IntStream.range(0, size)
  .forEach(idx -> {
      String movie = MOVIES.get(idx);
      // ... work with movie
      if (idx == size - 1) {
          myLastMovie.put(idx, movie);
      }
  });
assertEquals(1, myLastMovie.size());
assertTrue(myLastMovie.containsKey(size - 1));
assertTrue(myLastMovie.containsValue("No Country For Old Men"));

As we can see in the test, we used the IntStream.range(0, list.size()) method to initialize the list’s index stream. It’s worth noting that we used a Map object to store the last index and value for later verifications. This is because local variables used in lambdas must be final or effectively final.

正如我们在测试中看到的,我们使用 IntStream.range(0, list.size()) 方法初始化了列表的索引流。值得注意的是,我们使用了 对象来存储最后的索引和值,以便以后进行验证。这是因为 lambdas 中使用的局部变量必须是最终变量或有效最终变量

4. Using an External Counter

4.使用外部计数器

Alternatively, we can maintain an external counter variable to keep track of the iteration count. By comparing the counter with the size of the collection, we can determine the last iteration:

或者,我们可以维护一个外部计数变量来跟踪迭代次数。通过比较计数器和集合的大小,我们可以确定最后一次迭代:

int size = MOVIES.size();
String myLastMovie = null;
int cnt = 0;
for (String movie : MOVIES) {
    // ... work with movie
    if (++cnt == size) {
        myLastMovie = movie;
    }
}
assertEquals("No Country For Old Men", myLastMovie);

Compared to the IntStream solution, this approach is more straightforward.

IntStream 解决方案相比,这种方法更加简单明了。

5. Looping With an Iterator

5.使用 Iterator 循环

Although we have solved the problem in the IntStream and counter approaches, both solutions require introducing new variables and performing additional comparisons to detect the last iteration.

虽然我们通过 IntStreamcounter 方法解决了这个问题,但这两种解决方案都需要引入新变量并执行额外的比较,以检测最后一次迭代。

Next, let’s see how we can determine the last iteration while traversing the list using an Iterator.

接下来,让我们看看如何在使用 Iterator 遍历列表时确定最后一次迭代。

Iterator provides the hasNext() method, allowing us to check if the current iteration is the last conveniently. Therefore, we don’t need additional variables for this purpose:

Iterator 提供了 hasNext()方法,使我们可以方便地检查当前迭代是否是最后一次迭代。因此,我们不需要为此目的添加额外的变量:

String movie;
String myLastMovie = null;
for (Iterator<String> it = MOVIES.iterator(); it.hasNext(); ) {
    movie = it.next();
    // ... work with movie
    if (!it.hasNext()) { // the last element
        myLastMovie = movie;
    }
}
assertEquals("No Country For Old Men", myLastMovie);

As we can see, using an Iterator is an optimal choice to solve this problem.

我们可以看到,使用 Iterator 是解决这一问题的最佳选择。

6. Conclusion

6.结论

In this article, we’ve explored three approaches to identifying the last iteration while traversing a List using a for-each loop.

在本文中,我们探讨了在使用 for-each 循环遍历 List 时识别最后一次迭代的三种方法。

With its built-in hasNext() check, the Iterator approach can be an optimal solution to address this particular challenge.

通过内置的 hasNext() 检查,迭代器 方法可以成为应对这一特定挑战的最佳解决方案。

As always, the complete source code for the examples is available over on GitHub.

与往常一样,这些示例的完整源代码可在 GitHub 上获取。