【问题标题】:Field assignment in a Java foreach declarationJava foreach 声明中的字段分配
【发布时间】:2010-10-05 19:56:42
【问题描述】:

我知道以下示例中使用的 foreach 循环无法编译。但是有人知道为什么不允许在 foreach 循环声明中使用字段吗?

public class Foo {
    private Object obj;

    public void run(List<Object> objects) {
        for (obj : objects) {
            process();
        }
    }

    private void process() {
        // do something with obj
    }
}

【问题讨论】:

    标签: java foreach


    【解决方案1】:

    可能是因为

    • 限制循环变量的范围(从而使代码更清晰,并避免可能的细微错误),并且
    • 简化了编译器的解析。

    【讨论】:

    • 我想知道设计人员是否也在考虑将来扩展修改后的 for 循环,以便为循环变量的不同值运行主体的并行执行。如果变量存在于循环之外,如果不实现第三种 for 循环,就很难添加此功能。
    • @Rich:无论如何,这很难适应当前的语义,因为您目前可以保证元素的顺序与集合迭代器的顺序相同。我认为并行化要么会破坏这一点,要么会因过度同步而无用。
    • @Mark,考虑到元素访问顺序的保证,这是有道理的。我一直对循环的顺序感到不安。感谢您减轻我的负担。
    【解决方案2】:

    在 foreach 循环中分配给字段通常没有意义。 foreach 循环中对象的范围只是循环的一次迭代,而字段的范围是对象的生命周期。

    你真的应该把每个对象作为参数传递给process()...你不会通过将引用存储为字段来获得任何东西。另外,如果你真的想要,你可以使用 this.obj = obj 手动分配给一个字段。

    【讨论】:

    • 我同意字段描述对象的状态。但是,如果类的实例只存在于 Web 应用程序的请求期间,则使用字段而不是局部变量是完全可以的。
    • @kraftan 问题是,循环本身对于单个方法调用仍然是本地的。因此,循环中使用的变量也应该是本地的。最小化事物的范围(包括变量)是一个很好的设计,并且考虑到这可能会引入很多很多潜在的问题(如果你不使用该字段,可能会避免可怕的线程安全问题)他们明智地选择不允许这样的事情发生。我怀疑它是否被考虑过。
    • 我同意。一般不允许这样的事情绝对是明智的。
    【解决方案3】:

    我认为有几个原因,但这可能只是为了防止程序员出错。

    有一件令人困惑的事情是“循环执行后 obj 的值是多少”?与标准的 for 循环不同,增强的 for-each 循环并没有尝试对自己的机制做出保证。

    另一件事是实例字段表示对象的状态。在 for-each 循环中使用实例字段的意思是,在单个操作的过程中,对象可能会从一种状态更改为一种或多种中间状态,然后再更改为最终状态 。这只是糟糕的设计,值得预防。

    为什么不将 obj 作为参数传递给process()

    【讨论】:

      【解决方案4】:

      obj 在 for 循环运行之前应该有什么值,在循环运行之后它应该有什么值?这会令人困惑。

      【讨论】:

      • 它可以和普通for循环的循环变量一样:在循环之前它具有进入循环之前的任何值;在循环之后,它具有退出循环之前的最后一个值。并不是说这将是一个好主意或坏主意,实际上我倾向于同意@TedHopp 回答中提到的回应。我只是说它会像普通的 for 循环一样令人困惑或不令人困惑。
      【解决方案5】:

      早在 2004 年就有一个 bug report 在这个问题上。它被拒绝了,回复很有趣:

      通过强制在循环内声明循环变量来采取某种“安全第一”的方法(参见 JLS 14.14.2 中的翻译)。首先,不存在意外破坏封闭范围内的变量的危险。其次,如果变量由循环体传递给其他线程,则每次迭代都使用新的循环变量可以避免并发问题。第三,编译器可以通过将循环变量声明为“final”来进行优化。第四,如果封闭范围内的变量被重用为循环变量,并且程序员认为循环遍历整个集合,他们可能希望能够通过循环观察迭代后集合中的最后一个元素多变的。但它不一定指最后一个元素,例如如果循环中断了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-07
        • 1970-01-01
        • 2011-03-26
        相关资源
        最近更新 更多