【问题标题】:Nested For loop incrementing after termination嵌套 For 循环在终止后递增
【发布时间】:2014-04-12 14:35:13
【问题描述】:

我有 2 个 for 循环,一个嵌套在另一个循环中。它们循环遍历按钮的二维数组,以获取使用动作侦听器单击的每个按钮的源。

找到按钮后,我将按钮的位置/数组索引传递给外部方法。但是,当从按钮数组中找到按钮时,第一个 for 循环将其终止条件评估为 FALSE,但仍会增加 i 的值。导致一个错误。我的代码在标准操作执行方法中,“事件”是 ActionEvent。 button[][] 是一个定义为实例变量的 JButton 数组。它的大小为 10 x 10,并且已添加到面板中。

int i = 0; //this will loop through the columns in the array
int j  = 0; //loop through the rows
boolean locatedSource = false; //allows me to escape both loops

for(i = 0; !(locatedSource) && i < buttons.length; i++) //problem here, when i < buttons.length is FALSE i still gets incremented, leading to an off by one error
{
  for(j = 0; !(locatedSource) && j < buttons.length; j++)
  {
    if(event.getSource() == buttons[i][j])
    {
      locatedSource = true;
      break;
    }
  }
}
//do stuff with i and j in another method. Leads to array out of bounds error / off by one error
}

我应该提到,我不希望通过使用标签来解决这个问题,他们似乎不鼓励。

【问题讨论】:

    标签: java arrays for-loop break off-by-one


    【解决方案1】:

    问题说明

    for 循环的增量表达式在每次循环迭代之后 执行,而不是之前。请参阅Oracle Java tutorial 中的以下引用:

    for 语句提供了一种迭代一系列值的紧凑方法。程序员经常将其称为“for 循环”,因为它反复循环直到满足特定条件。 for语句的一般形式可以表示为:

    for (initialization; termination;
         increment) {
        statement(s)
    }
    

    使用此版本的 for 语句时,请记住:

    1. 初始化表达式初始化循环;它在循环开始时执行一次。
    2. 当终止表达式的计算结果为 false 时,循环终止。
    3. 每次循环迭代后都会调用增量表达式;这个表达式增加或减少一个值是完全可以接受的。

    For循环解决方案

    您可以重新编写循环,使增量是循环内的第一条语句。

        for (i = 0; !(locatedSource) && i < buttons.length;) {
            i++;
            for (j = 0; !(locatedSource) && j < buttons.length;) {
                j++;
                if (event.getSource() == buttons[i][j]) {
                    locatedSource = true;
                }
            }
        }
    

    While 循环版本

    鉴于循环变量都是在循环之外初始化的,并且您不想使用 for 循环增量表达式,因此重写代码以使用 while 循环可能会更清晰,如下所示:

        while (!(locatedSource) && i < buttons.length) {
            i++;
            while (!(locatedSource) && j < buttons.length) {
                j++;
                if (event.getSource() == buttons[i][j]) {
                    locatedSource = true;
                }
            }
        }
    

    【讨论】:

    • 我喜欢这个解决方案。你知道为什么我的代码会额外增加吗?
    • 我添加了 Oracle Java 教程中的一个引述,以便更清楚地了解发生了什么。
    【解决方案2】:

    三种可能的解决方案:

    1. 明确设置“找到”索引,不要重复使用您的 for 循环索引。
    2. 在自己的方法和return 直接从循环中搜索。
    3. 循环结束后将 i 减 1。

    【讨论】:

    • 我想我会实现单独的方法,你能解释一下为什么我会因为一个错误而失败吗?我不明白为什么。
    【解决方案3】:

    在内部循环中使用一些布尔标志设置它并在外部循环的开头检查它。

    代码如下:

        boolean found = false;
        for (i = 0; i < 10; i++) // problem here, when i < buttons.length is FALSE i still gets
                                 // incremented, leading to an off by one error
        {
            if (found) {
                i--;
                break;
            }
            for (j = 0; j < 5; j++) {
                if (i == 5 && j == 3) {
                    found = true;
                    break;
                }
            }
            //if (found) {               
            //    break;
            //}
        }
    

    【讨论】:

    • 我已经阅读了关于使用标签来阻止这个问题,但他们似乎非常不鼓励
    • 使用一些布尔标志在内部循环中设置它并在外部循环的开头检查它。
    • 这仍然会增加第一个循环(i),所以它是关闭的。
    • 我已经更新了您的代码以及我的答案。这取决于用于外部循环的 if 条件的位置。如果在内部循环的开头使用 -1,则使用 -1,因为它在外部循环中递增。
    【解决方案4】:

    您的代码包含注释“这里的问题,当 i

    首先执行循环更新块(如i++),然后检查条件(如`i

    意思是i == buttons.length是循环结束后没有触发locatedSource条件的正确状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 2018-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-12
      • 2013-01-12
      相关资源
      最近更新 更多