開發與維運

《Java 開發手冊》的前世今生

《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

更新亮點:首次向業界開放

Leave a Reply

Your email address will not be published. Required fields are marked *