2010-10-05 22 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'來進行優化。第四,如果封閉範圍中的變量被重用爲循環變量,並且程序員認爲循環遍歷整個集合,那麼他們可能希望能夠在迭代之後通過循環觀察集合中的最後一個元素變量。但它不一定是指最後一個元素,例如如果循環做了休息。