2008-11-25 171 views
57

在Java中,您可以使用final關鍵字限定局部變量和方法參數。爲什麼在Java中將局部變量和方法參數標記爲「final」?

public static void foo(final int x) { 
    final String qwerty = "bar"; 
} 

這樣做會導致無法在方法主體中重新分配x和qwerty。

這種做法將您的代碼推向通常被認爲是加號的不變性方向。但是,它也往往會在各處出現「最終」的代碼。對Java中局部變量和方法參數的最終關鍵字有什麼看法?

+2

請參閱http://stackoverflow.com/questions/266806/is-there-any-performance-reason-to-declare-method-parameters-final-in-java#266981和http://stackoverflow.com/ questions/137868/using-final-modifier-whenever-applicable-in-java and http://stackoverflow.com/questions/154314/when-to-use-final – Robin 2008-11-25 14:36:21

回答

53

你應該儘量做到這一點,只要它是適當的。除了用於在您「意外」嘗試修改值時發出警告,它還會向編譯器提供信息,以便更好地優化類文件。這是Robert Simmons,Jr所着的書「Hardcore Java」中的一個要點。實際上,本書的第二章全面介紹了使用final來促進優化並防止邏輯錯誤。靜態分析工具,如PMD和Eclipse的內置SA標記這些種情況出於這個原因。

27

我個人認爲,這是浪費時間。我相信視覺混亂和增加冗長是不值得的。

我從來沒有遇到過我已經重新分配(記住,這不會使對象不可變,所有這些都意味着您不能重新分配變量的另一個引用)錯誤的變量。

但是,當然,這全是個人喜好;-)

+5

+1因爲我認爲它不僅僅是方法身體和邏輯錯誤(我從來沒有跑過,因爲非最終變量,FWIW),但也關於可讀的方法簽名。我無法看到聲明爲final的參數如何使簽名更具可讀性。簡單類型通過值傳遞,所以不可修改。複雜類型是按引用傳遞的,但引用是按值傳遞的,因此不可修改。最後只是簽名的讀者的噪音。 – Matthias 2010-07-18 11:17:04

0

爲什麼你想要?您編寫了該方法,因此修改該方法的任何人都可以始終從qwerty中刪除最終的關鍵字並重新分配它。至於方法簽名,同樣的推理,儘管我不確定它會對你的類的子類做些什麼......他們可能會繼承最後一個參數,即使他們重寫了方法,也無法去定義x。試試看看它是否可行。

那麼,唯一真正的好處是如果你使參數不可變並且它傳遞給了孩子。否則,你只是混亂你的代碼沒有特別好的理由。如果它不會強迫任何人遵守你的規則,那麼你最好留下一個好評,因爲你爲什麼不應該改變該參數或變量,而不是給出最終修飾符。

編輯

在迴應評論,我會補充一點,如果你看到的性能問題,讓你的局部變量和參數可以最終讓編譯器來優化你的代碼更好。但是,從您的代碼不可變性的角度來看,我支持我的原始聲明。

+0

如果JRE或編譯器知道該對象已完成,則可以執行更多優化。 – paxdiablo 2008-11-25 04:25:46

+0

當然,但這不是問題。在使你的代碼不可變的方面,它並不真正起作用。但是,您的判斷非常正確,因爲它可能比不使用它稍快,並且在性能成爲問題時應予以考慮。 – Elie 2008-11-25 04:27:30

+0

正如我在Pax的回答中所評論的那樣,我相當肯定,通過局部變量的最終結果,沒有改進性能,因爲JVM可以爲你猜出。 – SCdF 2008-11-25 04:31:00

5

由於Java的「pass by reference」行爲(偶爾)混淆本質,我絕對同意最終確定參數var's。

完成本地var的似乎有點矯枉過正IMO。

6

在局部變量的情況下,我傾向於避免這種情況。它會導致視覺混亂,而且通常是不必要的 - 一個函數應該足夠短或集中在一個單一的影響,讓你很快看到你正在修改不應該的東西。

在幻數的情況下,我會把它們作爲一個常量私人字段,而不是在代碼中。

我只在需要的情況下使用final(例如,將值傳遞給匿名類)。

0

我讓Eclipse在匿名類中使用它,因爲我使用Google Collection API而增加了這個類。

0

如果我們認爲它們不會被重新分配或不應被重新分配,我們在這裏爲局部變量做這件事。

參數不是最終的,因爲我們有一個Checkstyle-Check檢查重新分配參數。當然,沒有人會想要重新分配參數變量。

2

最終有三個很好的理由:

  • 實例變量的構造函數只設置成爲不可改變
  • 方法不能被重寫成爲決賽中,真正的原因使用,默認情況下不
  • 局部變量或要在方法內部的不一致類中使用的參數需要是最終的

與方法類似,本地變量和參數不需要聲明爲final。就像其他人之前所說的那樣,這會使代碼變得越來越不可讀,編譯器性能優化的代價變得越來越小,這對大多數代碼片段來說並不是真正的原因。

3

是的。

這是關於可讀性。當你知道變量只被賦值一次而且只賦值一次時,更容易推斷程序的可能狀態。

一個體面的替代方法是在分配參數時或者多次分配變量(除了循環變量之外)時打開IDE警告。

8

使參數最終保證該方法中任何位置使用的值指傳遞的值。否則,你不得不精神分析給定位置上的所有代碼,以知道該參數在那個點上有什麼值。

因此,使用最終使你的代碼的可讀性和可維護,全部由自己:)

最後的局部變量取決於意圖,是在我的觀點不那麼重要了。取決於發生的情況。

2

雖然它造成了一點點混亂,但值得推薦final。 Ides例如eclipse可以自動將final設置爲如此。

2

製作局部變量和方法參數final是非常重要的,如果你想將這些參數傳遞給匿名類 - 就像你實例化一個匿名線程並且想要訪問run()方法體內的那些參數。

除此之外,我不確定通過編譯器優化可以獲得更好的性能。它是由具體的編譯器實現是否要優化它...

這將是很好的知道使用final任何性能統計...

相關問題