編碼規約(四)OOP 規約
所有內容摘自阿里巴巴的《Java開發手冊-嵩山版》
-
【強制】避免通過一個類的物件引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可。
-
【強制】所有的覆寫方法,必須加 @Override 註解。
說明:getObject() 與 get0bject() 的問題。一個是字母的 O,一個是數字的 0,加 @Override 可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編譯報錯。 -
【強制】相同引數型別,相同業務含義,才可以使用 Java 的可變引數,避免使用 Object。
說明:可變引數必須放置在引數列表的最後。(建議開發者儘量不用可變引數程式設計)
正例:listUsers(String type, Long... ids) {...} -
【強制】外部正在呼叫或者二方庫依賴的介面,不允許修改方法簽名,避免對介面呼叫方產生影響。介面過時必須加 @Deprecated 註解,並清晰的說明採用的新介面或者新服務是什麼。
-
【強制】不能使用過時的類或方法。
-
【強制】Object 的 equals 方法容易拋空指標異常,應使用常量或確定有值的物件來呼叫 equals。
說明:推薦使用 JDK7 引入的工具類 java.util.Objects#equals(Object A, Object B)
正例:"test".equals(object);
反例: -
【強制】所有整型包裝類物件之間值的比較,全部使用 equals 方法比較。
說明:對於 Integer var = ? 在 -128 至 127 之間的賦值,Integer 物件是在 IntegerCache.cache 產生,會複用已有物件,這個區間內的 Integer 值可以直接使用 == 進行判斷,但是這個區間之外的所有資料,都會在堆上產生,並不會複用已有物件,這是一個大坑,推薦使用 equals 方法進行判斷。 -
【強制】任何貨幣金額,均以最小貨幣單位且整型型別來進行儲存。
-
【強制】浮點數之間的等值判斷,基本資料型別不能用 == 來比較,包裝資料型別不能用 equals 來判斷。
說明:
正例:
(1)指定一個誤差範圍,兩個浮點數的差值在此範圍之內,則認為是相等的。
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
float diff = 1e - 6F;
if (Math.abs(a - b) < diff) {
System.out.println("true");
}
(2)使用 BigDecimal 來定義值,再進行浮點數的運算操作。
BigDecimal a = new BigDecimal("1.0");
BigDecimal a = new BigDecimal("0.9");
BigDecimal a = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal x = a.subtract(b);
if (x.compareTo(y) == 0) {
System.out.println("true");
}
反例:
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
if (a == b) {
// 預期進入此程式碼塊,執行其它業務邏輯
// 但事實上 a==b 的結果為 false
}Float x = Float.valueOf(a);
Float y = Float.valueOf(b);
if (x.equals(b)) {
// 預期進入此程式碼塊,執行其它業務邏輯
// 但事實上 a==b 的結果為 false
} -
【強制】如上所示 BigDecimal 的等值比較應使用 compareTo() 方法,而不是 equals() 方法。
說明:equals() 方法會比較值和精度(1.0 與 1.00 返回結果為 false),而 compareTo() 則會忽略精度。 -
【強制】定義資料物件 DO 類時,屬性型別要與資料庫欄位型別相匹配。
正例:資料庫欄位的 bigint 必須與類屬性的 Long 型別相對應。
反例:某個案例的資料庫表 id 欄位定義型別 bigint unsigned,實際類物件屬性為 Integer,隨著 id 越來越大,超過 Integer 的表示範圍而溢位成為負數。 -
【強制】禁止使用構造方法 BigDecimal(double) 的方式把 double 值轉化為 BigDecimal 物件。
說明:BigDecimal(double) 存在精度損失風險,在精確計算或值比較的場景中可能會導致業務邏輯異常。
正例:優先推薦入參為 String 的構造方法,或使用 BigDecimal 的 valueOf 方法,此方法內部其實執行了 Double 的 toString,而 Double 的 toString 按 double 的實際能表達的精度對尾數進行了截斷。 -
關於基本資料型別與包裝資料型別的使用標準如下:
1)【強制】所有 POJO 類屬性必須使用包裝資料型別。
2)【強制】RPC 方法的返回值和引數必須使用包裝資料型別。
3)【強制】所有的區域性變數使用基本資料型別。
說明:POJO 類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式的賦值,任何 NPE 問題,或者入庫檢查,都由使用者來保證。
正例:資料庫的查詢結果可能是 null,因為自動拆箱,用基本資料型別接收有 NPE 風險。
反例:某業務的交易報表上顯示成交總額漲跌情況,即正負 x%,x 為基本資料型別,呼叫的 RPC 服務,呼叫不成功時,返回的是預設值,頁面顯示為 0%,這是不合理的,應該顯示成中劃線 -。所以包裝資料型別的 null 值,能夠表示額外的資訊,如:遠端呼叫失敗,異常退出。 -
【強制】定義 DO/DTO/VO 等 POJO 類時,不要設定任何屬性預設值。
反例:POJO 類的 createTime 預設值為 new Date(),但是這個屬性在資料提取時並沒有置入具體值,在更新其它欄位時又附帶更新了此欄位,導致建立時間被修改成當前時間。 -
【強制】序列化類新增屬性時,請不要修改 serialVersionUID 欄位,避免反序列失敗;如果完全不相容升級,避免反序列化混亂,那麼請修改 serialVersionUID 值。
說明:注意 serialVersionUID 不一致會丟擲序列化執行時異常。 -
【強制】構造方法裡禁止加入任何業務邏輯,如果有初始化邏輯,請放在 init 方法中。
-
【強制】POJO 類必須寫 toString 方法。使用 IDE 中的工具:source > generate toString 時,如果繼承了另一個 POJO 類,注意在前面加一下 super.toString。
說明:在方法執行丟擲異常時,可以直接呼叫 POJO 的 toString() 方法列印其屬性值,便於排查問題。 -
【強制】禁止在 POJO 類中,同時存在對應屬性 xxx 的 isXxx() 和 getXxx() 方法。
說明:框架在呼叫屬性 xxx 的提取方法時,並不能確定哪一個方法一定是被優先呼叫到的。 -
【推薦】使用索引訪問用 String 的 split 方法得到的陣列時,需做最後一個分隔符後有無內容的檢查,否則會有拋 IndexOutOfBoundsException 的風險。
-
【推薦】當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序放置在一起,便於閱讀,此條規則優先於下一條。
-
【推薦】類內方法定義的順序依次是:公有方法或保護方法 > 私有方法 > getter/setter方法。
說明:公有方法是類的呼叫者和維護者最關心的方法,首屏展示最好;保護方法雖然只是子類關心,也可能是“模板設計模式”下的核心方法;而私有方法外部一般不需要特別關心,是一個黑盒實現;因為承載的資訊價值較低,所有 Service 和 DAO 的 getter/setter 方法放在類體最後。 -
【推薦】setter 方法中,引數名稱與類成員變數名稱一致,this.成員名 = 引數名。在 getter/setter 方法中,不要增加業務邏輯,增加排查問題的難度。
-
【推薦】迴圈體內,字串的連線方式,使用 StringBuilder 的 append 方法進行擴充套件。
說明:下例中,反編譯出的位元組碼檔案顯示 每次迴圈都會 new 出一個 StringBuilder 物件,然後進行 append 操作,最後通過 toString 方法返回 String 物件,造成記憶體資源浪費。
反例:
String str = "start";
for (int i=0;i < 100;i++) {
str = str + "hello";
} -
【推薦】final 可以宣告類、成員變數、方法、以及本地變數,下列情況使用 final 關鍵字:
1)不允許被繼承的類,如:String 類。
2)不允許修改引用的域物件,如:POJO 類的域變數。
3)不允許被覆寫的方法,如:POJO 類的 setter 方法。
4)不允許執行過程中重新賦值的區域性變數。
5)避免上下文重複使用一個變數,使用 final 關鍵字可以強制重新定義一個變數,方便更好的進行重構。 -
【推薦】慎用 Object 的 clone 方法來拷貝物件。
說明:物件 clone 方法預設是淺拷貝,若想實現深拷貝,需覆寫 clone 方法實現域物件的深度遍歷式拷貝。 -
【推薦】類成員與方法訪問控制從嚴:
1)如果不允許外部直接通過 new 來建立物件,那麼構造方法必須是 private。
2)工具類不允許有 public 或 default 構造方法。
3)類非 static 成員變數並且與子類共享,必須是 protected。
4)類非 static 成員變數並且僅在本類使用,必須是 private。
5)類 static 成員變數如果僅在本類使用,必須是 private。
6)若是 static 成員變數,考慮是否為 final。
7)類成員方法只供內部呼叫,必須是 private。
8)類成員方法只對繼承類公開,那麼限制為 protected。
說明:任何類、方法、引數、變數,嚴控訪問範圍。過於寬泛的訪問範圍,不利於模組解耦。思考:如果是一個 private 的方法,想刪除就刪除,可是一個 public 的 service 成員方法或成員變數,刪除一下,不得手心冒點汗嗎?變數像自己的小孩,儘量在自己的視線內,變數作用域太大,無限制的到處跑,那麼你會擔心的。
作者:金木研King
轉載請註明原文連結:https://www.cnblogs.com/jinzlblog/p/15236213.html