Java開發中常見的危險訊號

spasvo發表於2013-12-19

  Dustin Marx是一位專業軟體開發者,從業已經有17年的時間,他擁有電子工程學士學位,還是一位MBA。Dustin維護著一個部落格,專門介紹軟體開發的各個 主題。近日,他撰文談到了Java開發中常見的危險訊號,提出了在日常的Java開發中我們需要盡力避免的一些不正確的做法。

  經過多年的開發、閱讀、回顧並維護了數萬行的Java程式碼後,我經常會看到中 出現的某些“危險訊號”,這些訊號經常(但也許並不總是)暗示著程式碼出現了某些問題。我這裡所要談的並不是那些總是錯誤的實踐,而是想要談談在某些場景下 可能是恰當,但通常卻會導致問題的一些實踐。這些“危險訊號”有時可能並沒有問題,但卻會造成問題的積累,並最終導致問題的產生。這裡我總結出了一些“危 險訊號”,並且談談在哪些情況下他們是沒有問題的,在哪些情況下則會導致問題。

  這裡將要談及的很多“危險訊號”通常都會收到來自於FindBugs等程式碼分析工具所發出的警告資訊,流行的Java IDE也會將它們標記出來。不過,我發現有不少開發者會忽略掉這些來自於工具與IDE的警告資訊,要麼是因為他們關掉了提示資訊,要麼是出於自身的開發習 慣或是不理解與這些警告資訊所關聯的風險,因此會忽略掉警告資訊。

  對引用使用==(而不是.equals)

  很多Java開發者都知道使用==比較原生型別資料,使用.equals比較引用型別資料。這是一條很容易記住的簡單原則,Java開發者這麼 用也沒什麼問題。有時使用==來比較標準的Java型別引用(String、Integer、Long等等)也沒問題,不過這要取決於被快取的值的大小, 因此這麼做並不是一個好的做法。有時,我們需要檢查標識的相等性而不是內容的相等性,在這種情況下使用==來比較引用就很適合了。相對而言,我更喜歡 Groovy的處理方式,==類似於.equals,而===則是更加嚴格地比較標識。同理,使用!=來比較兩個引用也是一個“危險訊號”,因為如果待比 較的兩個物件不共享相同的標識(記憶體地址),即便他們擁有相同的內容也總是會返回true。

  對列舉使用.equals(而不是==)

  坦率地說,對於列舉,Java開發者使用==還是.equals都沒有太大關係。不過,我更傾向於對列舉使用==。這麼做最重要的原因就是對枚 舉使用==可以防止不小心將列舉與不相關的物件進行比較(永遠不會相等)。Object.equals(Object)方法可以接收任意物件,這意味著編 譯器並不會強制限定傳進來的物件要與被比較的物件是相同的型別。一般來說,我更喜歡靜態的編譯期問題檢測而非動態執行期的問題檢測,對列舉使用==可以滿 足這個要求。同理,在比較列舉時,!=與!.equals也是一樣的。

  魔數與字串字面值

  我經常會在Java程式碼中看到有人使用“魔數”和字串字面值。他們對於未來的維護來說是一種“危險訊號”,讓我十分懷疑應用的正確性。在單個 位置處將其標識為常量(如果可能用列舉來表示更佳),這麼做可以改善未來的維護,並且讓我可以更加自信地相信使用這些值的所有程式碼都在使用著相同的值。除 此之外,在一個地方定義好常量與列舉可以更方便地使用IDE的“查詢使用”特性來找到所有使用這些常量的地方。

  常量

  在看到有限的相關字串常量時,我就在想使用列舉應該更加適合。對於高度內聚的字串常量的情況來說更是如此,因為列舉可以更好地表達出這些字 符串所表示的概念。相比於字串常量來說,列舉提供了編譯期的靜態型別安全與潛在的效能優勢。對於程式的正確性來說,編譯期的安全是最吸引我的地方。

  使用Java的“goto”

  很少有人會使用標籤程式碼,如果使用了那也說明用法不當。換句話說,如果使用了也是濫用而已。在大多數情況下,使用Java的“goto”會造成程式碼的可讀性極差。

  根據作用域來確定恰當的變數引用

  我認為這種方式永遠都是不恰當的,但它卻能執行,甚至有時是被某些Java開發者有意而為之。比如說,者 將傳遞進方法的變數在方法執行時指向了另一個引用。該變數(臨時指向方法引數)指向了另一個引用,直到方法結束為止,這時它脫離了作用域。在這種情況下, 在方法簽名的引數定義前加上final關鍵字會導致編譯器錯誤,這也是我喜歡在方法引數前加上final的原因之一。對於我來說,在方法中宣告一個新的局 部變數是更加清晰且可讀的方式,因為它只能在方法中使用。更為重要的是,作為程式碼的讀者,我不知道是開發者有意希望該引數名只是指向一個不同的值還是引入 了Bug,因為將引數重新指向新的引用實際上會改變呼叫端的值。如果我看到有人這麼寫,那麼我就會找程式碼的編寫者或是透過單元測試來驗證程式碼的意圖。

  equals(Object)與hashCode()方法的不匹配

  雖然我認為每個Java類都應該重寫toString()方法,但對於equals(Object)與hashCode()方法來說卻並不這麼 認為。我覺得只有在需要這些方法的場合下才應該重寫類中的這兩個方法,因為他們的存在暗示著其設計與開發某種程度上的完全改變。特別地,equals與 hashCode方法要能滿足其意圖與契約(位於Object類的API文件),並且需要保持一致。大多數IDE與分析工具都會在其中一個方法重寫而另一 個沒有重寫的情況下給出提示。然而,我要確保equals與hashCode使用的是相同的屬性,並且在這兩個方法中屬性的順序要保持一致。

本文轉自:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29379530/viewspace-1063783/,如需轉載,請註明出處,否則將追究法律責任。

相關文章