2010-10-05 21 views
3

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

public class Foo { 
    private Object obj; 

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

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

回答

1

我期望有几个原因,但它可能只是为了防止程序员错误。

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

另一件事是实例字段代表一个对象的状态。通过在for-each循环中使用实例字段,你会说的是,对象可以从一个状态改变为一个或多个中间状态,然后在单个操作的过程中最终到达状态。这只是糟糕的设计,值得预防。

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

2

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

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

+0

我同意字段描述对象的状态。但是,如果该类的实例只在Web应用程序的请求期间存在,则使用字段而非局部变量非常合适。 – kraftan 2010-10-06 19:21:05

+1

@kraftan事情是,循环本身仍然是本地的一个方法调用。因此,循环中使用的变量也应该是本地的。最大限度地减少事物的范围(包括变量)是很好的设计,并且考虑到许多潜在的问题,这将有可能引入(如果你不使用该领域,将会有可怕的线程安全问题)明智地选择不允许这样的事情。我怀疑它甚至被考虑。 – ColinD 2010-10-06 21:02:00

+0

我同意。一般来说不允许这样的事情绝对是明智的。 – kraftan 2010-10-07 06:43:54

7

可能是因为它

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

我不知道设计师是否也在考虑未来扩展修改后的for循环,以便为循环变量的不同值执行主体的并行执行。如果变量存在于循环之外,那么添加此功能将很困难,而不实现第三种for循环。 – Rich 2010-10-05 20:08:06

+3

@Rich:无论如何,这很难适应当前的语义,因为你目前可以保证元素的顺序与集合迭代器的顺序相同。我认为并行会破坏或者通过过度同步而无用。 – 2010-10-05 20:10:38

+0

@Mark,考虑到元素访问顺序的保证是有道理的。我一直对循环的顺序感到不安。谢谢你的举重减轻我的肩膀。 – Rich 2010-10-05 20:14:19

1

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

+0

它可能与普通for循环的循环变量相同:在循环之前它具有进入循环之前的任何值;循环之后它具有退出循环之前的最后一个值。不要说这将是一个好的或坏的想法,实际上我倾向于赞同@TedHopp答案中提到的回应。我只是说它会像普通的for循环一样令人困惑或无法混淆。 – SantiBailors 2016-12-09 10:42:15

1

有关于这个问题早在2004年,被拒绝bug report和响应有趣的是:

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