《Java 開發手冊》始發於阿里巴巴內部規約,涵蓋編程規約、異常日誌、單元測試、安全規約等七大維度。從 2017 年上線至今整整四年,共發佈了七個版本,在全球 Java 開發者共同努力下,這本手冊已經成為業界普遍遵循的開發規範,感謝大家一直和我們在碼出高效、碼出質量的路上並肩同行。
本文將介紹每個版本手冊更新的亮點,文末可以下載所有版本的合集。
第七版:泰山版《Java 開發手冊》
更新日期:2020/04/22
更新亮點:
- 新增 5 條日期時間規約
- 新增 2 條表別名 sql 規約
- 新增統一錯誤碼規約
新增的規約細則如下:
OOP 規約
1.【強制】任何貨幣金額,均以最小貨幣單位且整型類型來進行存儲。
2.【推薦】當某個方法的代碼行數超過 10 行時,return / throw 等中斷邏輯的右大括號後加一個空行。
說明:這樣做邏輯清晰,有利於代碼閱讀時重點關注。
3.【推薦】在類中刪除未使用的任何字段和方法;在方法中刪除未使用的任何參數聲明與內部變量。
4.【強制】三目運算符 condition? 表達式1 : 表達式2 中,高度注意表達式 1 和 2 在類型對齊時,可能拋出因自動拆箱導致的 NPE 異常。
說明:以下兩種場景會觸發類型對齊的拆箱操作:
- 表達式 1 或表達式 2 的值只要有一個是原始類型。
- 表達式 1 或表達式 2 的值的類型不一致,會強制拆箱升級成表示範圍更大的那個類型。
日期時間
1.【強制】在日期格式中分清楚大寫的 M 和小寫的 m,大寫的 H 和小寫的 h 分別指代的意義。
說明:日期格式中的這兩對字母表意如下:
- 表示月份是大寫的 M;
- 表示分鐘則是小寫的 m;
- 24 小時制的是大寫的 H;
- 12 小時制的則是小寫的 h。
2.【強制】不允許在程序任何地方中使用:1)java.sql.Date 2)java.sql.Time 3) java.sql.Timestamp。
說明:第 1 個不記錄時間,getHours() 拋出異常;第 2 個不記錄日期, getYear() 拋出異常;第 3 個在構造方法 super((time/1000)*1000),fastTime 和 nanos 分開存儲秒和納秒信息。
3.【強制】不要在程序中寫死一年為 365 天,避免在公曆閏年時出現日期轉換錯誤或程序邏輯錯誤。
4.【推薦】避免公曆閏年 2 月問題。閏年的 2 月份有 29 天,一年後的那一天不可能是 2 月 29 日。
5.【推薦】使用枚舉值來指代月份。如果使用數字,注意 Date,Calendar等日期相關類的月份 month 取值在 0-11 之間。
說明:參考 JDK 原生註釋,Month value is 0-based. e.g., 0 for January.
集合處理
1.【強制】判斷所有集合內部的元素是否為空,使用 isEmpty() 方法,而不是 size()==0 的方式。
說明:前者的時間複雜度為 O(1),而且可讀性更好。
2.【強制】在使用 java.util.stream.Collectors 類的 toMap() 方法轉為 Map 集合時,一定要使 用含有參數類型為 BinaryOperator,參數名為 mergeFunction 的方法,否則當出現相同 key 值時會拋出 IllegalStateException 異常。
說明:參數 mergeFunction 的作用是當出現 key 重複時,自定義對 value 的處理策略。
3.【強制】在使用 java.util.stream.Collectors 類的 toMap() 方法轉為 Map 集合時,一定要注意當 value 為 null 時會拋 NPE 異常。
說明:在 java.util.HashMap 的 merge 方法裡會進行如下的判斷:
if (value == null || remappingFunction == null) throw newNullPointerException();
SQL 規約
1.【強制】對於數據庫中表記錄的查詢和變更,只要涉及多個表,都需要在列名前加表的別名(或表名)進行限定。
說明:對多表進行查詢記錄、更新記錄、刪除記錄時,如果對操作列沒有限定表的別名(或表名),並且操作列在多個表中存在時,就會拋異常。
2.【推薦】SQL 語句中表的別名前加 as,並且以 t1、t2、t3、... 的順序依次命名。
說明:1)別名可以是表的簡稱,或者是根據表出現的順序,以 t1、t2、t3 的方式命名。2)別名前加 as 使別名更容易識別。
3.【強制】日誌打印時禁止直接用 JSON 工具將對象轉換成 String。說明:如果對象裡某些 get 方法被重寫,存在拋出異常的情況,則可能會因為打印日誌而影響正常業務流程的執行。
4.【強制】生產環境禁止直接使用 System.out 或 System.err 輸出日誌或使用 e.printStackTrace() 打印異常堆棧。
說明:標準日誌輸出與標準錯誤輸出文件每次 Jboss 重啟時才滾動,如果大量輸出送往這兩個文件,容易造成文件大小超過操作系統大小限制。
其他
1.【強制】避免用 Apache Beanutils 進行屬性的 copy。
說明:Apache BeanUtils 性能較差,可以使用其他方案比如 Spring BeanUtils, Cglib BeanCopier,注意均是淺拷貝。
安全規約
1.【強制】URL 外部重定向傳入的目標地址必須執行白名單過濾。
二方庫規約
1.【推薦】不要使用不穩定的工具包或者 Utils 類。
說明:不穩定指的是提供方無法做到向下兼容,在編譯階段正常,但在運行時產生異常,因此,儘量使用業界穩定的二方工具包。
設計規約
1.【參考】可擴展性的本質是找到系統的變化點,並隔離變化點。
說明:世間眾多設計模式其實就是一種設計模式即隔離變化點的模式。
2.【參考】代碼即文檔的觀點是錯誤的,清晰的代碼只是文檔的某個片斷,而不是全部。
說明:代碼的深度調用,模塊層面上的依賴關係網,業務場景邏輯,非功能性需求等問題是需要相應的文檔來完整地呈現的。
錯誤碼統一
統一錯誤碼,就是統一度量衡,為你的應用與服務的穩定保駕護航,煩惱清空,快樂回家。泰山版新近出爐的錯誤碼具有快速溯源、簡單易記、溝通標準化三大優勢。錯誤碼為字符串類型,共 5 位,分成兩個部分:錯誤產生來源和四位數字編號。錯誤產生來源分為 A/B/C,以當前代碼運行視角來進行判定,A 表示錯誤來源於用戶,比如請求參數錯誤,用戶安裝版本過低等問題;B 表示錯誤來源於當前系統,往往是業務邏輯出錯,或程序健壯性差等問題;C 表示錯誤來源於第三方服務,比如 CDN 服務出錯,消息投遞超時等問題。優秀的錯誤碼可以迅速知道他們是怎麼來滴,從哪兒來滴,來幹啥滴。同時俺們的錯誤碼具有三級結構,分為一級宏觀錯誤碼、二級宏觀錯誤碼、三級宏觀錯誤碼,這樣的方案更加可擴展,有彈性,更多詳細規則,見手冊的附件的《錯誤碼參考列表》。
Java 開發手冊所有歷史版本
第 6 版:華山版《Java 開發手冊》
更新日期:2019/06/13
更新亮點:
- 新增 21 條設計規約
- 修改描述 112 處
- 完善若干處示例
第 5 版:1.4.0 版 《阿里巴巴 Java 開發手冊》
更新日期:2018/06/06
更新亮點:新增 16 條設計規約
第 4 版:1.3.0 版 《阿里巴巴 Java 開發手冊》
更新日期:2017/09/19
更新亮點:增加單元測試規約
第 3 版:1.2.0 版 《阿里巴巴 Java 開發手冊》
更新日期:2017/05/20
更新亮點:公開徵集意見後修正版本
第 2 版:1.1.0 版 《阿里巴巴 Java 開發手冊》
更新日期:2017/02/27
更新亮點:增加前言和專有名詞說明,修正部分描述
第 1 版:1.0.0 版 《阿里巴巴 Java 開發手冊》
更新日期:2016/12/07
更新亮點:首次向業界開放