最近有做簡單的代碼規范整理,寫一下規范過程使用的工具和遇見比較多的問題。
關於代碼規范的重要性網上一搜一大堆,都是很有年代的一些文章,現在寫這個好像有點太low了,簡單列一下他們(相似的文章太多,找不到原文)所說到的幾點好處:
- 有助於團隊合作
- 減少BUG處理
- 降低維護成本
- 有助於代碼審查
- 養成規范代碼的習慣,有助於程序員自身的成長
毋庸置疑的是隨着團隊的發展、規范化,良好的代碼規范能體現的好處會越來越明顯,提升工作效率、提高代碼質量等等...
為了保證代碼的規范、質量,需要開發者自身養成良好的編碼習慣,但是很多時候每個人的風格習慣都不一樣,不利於團隊協作,即使有些公司會有人工代碼審查的環節,但是過於耗費人力資源,所以更多的是利用工具進行掃描分析。
代碼分析包括靜態分析和動態調試:
- 靜態分析:指在不運行程序的情況下,對源代碼進行檢查分析,通過分析語法、結構、過程、接口等來檢查程序的正確性,找出代碼中存在的錯誤和缺陷。如參數不匹配、有歧義的嵌套語句、錯誤的遞歸、非法計算、可能出現的空指針引用等等。
- 動態調試:指利用調試器跟蹤軟件的運行,尋找程序中的漏洞。
現在主要是利用以靜態分析技術實現的相關工具對代碼進行檢查,先列一下接觸到的工具:
工具 | 分析對象 | 備注 |
Findbugs | 字節碼文件 | 缺陷模式匹配、數據流分析。通過字節碼分析代碼存在缺陷、支持數據流分析,能查找出空指針崩潰等問題。 |
CheckStyle | Java源代碼 | 缺陷模式匹配。掃描代碼格式規范、代碼風格的工具。 |
Alibaba java coding guidelines(基於PMD) | Java源代碼 | 缺陷模式匹配、數據流分析。檢測代碼潛在錯誤。 |
- FindBugs
FindBugs是一個開源的靜態代碼分析工具,基於LGPL開源協議,它檢查類或者JAR 文件,將字節碼與一組缺陷模式進行對比以發現可能的問題。它注重檢測真正的bug及潛在的性能問題 ,尤其注意了盡可能抑制誤檢測(false positives)的發生,不關心代碼風格格式的問題。FindBugs的檢測結果主要分一下幾種問題類型:
-
- 正確性(Correctness):可能導致錯誤的代碼。比如錯誤的強制類型轉換。
- 最佳實踐反例(Bad practice):違反了公認的最佳實踐標准。如一些流使用后沒有關閉。
- 多線程的正確性(Multithreaded correctness):關注於同步和多線程問題。如應該使用notify()而不是notifyAll()。
- 性能(Performance):潛在的性能問題。如:一個屬性從沒有被使用,考慮從類中去掉。
- 危險的(Dodgy):具有潛在危險的代碼,可能運行期產生錯誤。如:對方法調用的直接引用,而方法可能返回null。
- 惡意代碼漏洞(Malicious code vulnerability):可能受到惡意攻擊的代碼,如訪問權限修飾符的定義等。
- 國際化(Internationalization):關於代碼國際化相關方面的。如使用平台默認的編碼格式對字符串進行大小寫轉換,這可能導致國際字符的轉換不當。
簡單列幾個我們程序中FindBugs分析出現比較多的問題:
- May expose internal representation by returning reference to mutable object.
可能因使引用可指向多個對象而暴露內部存儲結構。
get/set方法直接把此對象中某一屬性的引用放到外部,可以隨便更改,違反了封裝的原則。可以在get/set方法中修改為對這類屬性(引用地址)的拷貝對象做操作。但是一般不會這么做,實際使用中bean里面的屬性設置后很少會再改動,這么做太麻煩了。
- Method invokes inefficient Number constructor; use static valueOf instead.
方法調用低效數構造函數,使用靜態valueOf方法代替。
FindBugs推薦使用Integer.ValueOf(int)代替new Integer(int),因為這樣可以提高性能。如果當你的int值介於-128~127時,Integer.ValueOf(int)的效率比Integer(int)快大約3.5倍。從源代碼可以看到,ValueOf對-128~127這256個值做了緩存(IntegerCache),如果int值的范圍是:-128~127,在ValueOf(int)時,他會直接返回IntegerCache的緩存。
-
Boxed value is unboxed and then immediately reboxed.
裝箱的值被拆箱,然后立即重新裝箱了。自動裝箱拆箱的特性,只要運算中有不同類型,當涉及到類型轉換時,編譯器就會向下轉型,再運算。
-
Switch statement found where default case is missing.
Switch沒有默認情況下執行的case語句。 -
Inefficient use of keySet iterator instead of entrySet iterator.
使用 entrySet 遍歷 Map 類集合 KV,而不是 keySet 方式進行遍歷。當程序中有遍歷對map的key、value操作的時候,建議使用entrySet,它的性能比keySet高。通過keySet遍歷時,生成KeyIterator迭代器,如果要獲取value此時還要遍歷Map。而entrySet遍歷生成EntryIterator 迭代器,其中包含key和value。
-
Method call passes null for non-null parameter.
對參數為null的情況沒做處理。當args為空時,程序異常。
- Checkstyle
Checkstyle是一款檢查Java程序源代碼樣式的工具。主要的檢查項包括Javadoc注釋、命名規范、多余沒用的Imports、Size度量,如過長的方法、缺少必要的空格Whitespace、重復代碼等。它可以有效的幫助我們檢視代碼以便更好的遵循代碼編寫標准,特別適用於小組開發時彼此間的樣式規范和統一。
按照Sun的規范太嚴格了,通常需要自定義規則,使用起來很麻煩,所以后面沒有使用Checkstyle。
- Alibaba java coding guidelines
Alibaba java coding guidelines是阿里巴巴2017年10月在杭州雲棲大會上發布的,把《阿里巴巴 Java 開發規約》強制條目轉化為自動插件,並實現了部分的自動編碼。項目已經在Git上開源了,地址阿里規約插件。
阿里規約插件檢查的內容參照《阿里巴巴 Java 開發規約》,基於PMD進行的代碼檢測,檢測的問題主要分為三類,對應 Snoar 中的前三個等級,前兩個級別是必須要處理的:
-
- Blocker:崩潰
- Critical:嚴重
- Major:重要
按照阿里規約,大量存在的問題如下,因為是中文的,而且提示信息很准確,所以修改很輕松:
-
- 方法名、參數名、成員變量、局部變量都統一使用 lowerCamelCase 風格,必須遵從駝峰形式。
- 常量命名全部大寫,單詞間用下划線隔開,力求語義表達完整清楚,不要嫌名字長。
- 魔法值。
- 代碼中的命名均不能以下划線或美元符號開始,也不能以下划線或美元符號結束。
- 注釋的雙斜線與注釋內容之間有且僅有一個空格。
- Object 的 equals 方法容易拋空指針異常,應使用常量或確定有值的對象來調用 equals。
- 集合初始化時,指定集合初始值大小。
- 需要進行參數校驗。
- 類、類屬性、類方法的注釋必須使用 Javadoc 規范,使用/**內容*/格式。
其實單從這里並不能很好的做到代碼規范統一,了解到正常的應該是類似Jenkins+SonarQube+Git的方式,在提交代碼的時候會觸發檢查,不合規范的代碼不允許提交。