阿里Java編程規(guī)約【四】OOP規(guī)約

1. 【強制】避免通過一個類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法紊扬,無謂增加編譯器解析成本,直接用 類名來訪問即可固棚。

2. 【強制】所有的覆寫方法都弹,必須加 @Override 注解。

說明:getObject()get0bject() 的問題锣杂。一個是字母的 O脂倦,一個是數(shù)字的 0,加 @Override 可以準確判斷是否覆蓋 成功元莫。另外赖阻,如果在抽象類中對方法簽名進行修改,其實現(xiàn)類會馬上編譯報錯踱蠢。

3. 【強制】相同參數(shù)類型火欧,相同業(yè)務含義棋电,才可以使用的可變參數(shù),參數(shù)類型避免定義為 Object苇侵。

說明:可變參數(shù)必須放置在參數(shù)列表的最后赶盔。(建議開發(fā)者盡量不用可變參數(shù)編程)
正例:public List<User> listUsers(String type, Long... ids) {...}

4. 【強制】外部正在調用的接口或者二方庫依賴的接口,不允許修改方法簽名榆浓,避免對接口調用方產生影 響于未。接口過時必須加 @Deprecated 注解,并清晰地說明采用的新接口或者新服務是什么陡鹃。

  • 設計時沒有考慮周全烘浦,需要改造接口,需要通過增加新接口萍鲸,遷移后下線老接口的方式實現(xiàn)闷叉。
  • REST接口只能增加參數(shù),不能減少參數(shù)脊阴,返回值的內容也是只增不減握侧。

5. 【強制】不能使用過時的類或方法。

說明:java.net.URLDecoder 中的方法 decode(String encodeStr) 這個方法已經過時蹬叭,應該使用雙參數(shù) decode(String source, String encode)藕咏。接口提供方既然明確是過時接口,那么有義務同時提供新的接口秽五;作為調用方來說孽查,有義務去考證過時方法的新實現(xiàn)是什么。

6. 【強制】Object 的 equals 方法容易拋空指針異常坦喘,應使用常量或確定有值的對象來調用 equals盲再。

正例:"test".equals(param);
反例:param.equals("test");
說明:推薦使用 JDK7 引入的工具類 java.util.Objects#equals(Object a, Object b)

Java7 源碼如下所示:

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

7.【強制】所有整型包裝類對象之間值的比較,全部使用 equals 方法比較瓣铣。

說明:對于 Integer var = ? 在 -128 至 127 之間的賦值答朋,Integer 對象是在 IntegerCache.cache 產生,會復用已有對 象棠笑,這個區(qū)間內的 Integer 值可以直接使用 == 進行判斷梦碗,但是這個區(qū)間之外的所有數(shù)據(jù),都會在堆上產生蓖救,并不會復 用已有對象洪规,這是一個大坑,推薦使用 equals 方法進行判斷循捺。

我的批注:相信有經驗的開發(fā)者都應該知道字符串 String 比較肯定用的是 equals斩例。
Java 世界里相等請用equals方法,== 表示對象相等从橘,一般在框架開發(fā)中會用到念赶。

8. 【強制】任何貨幣金額础钠,均以最小貨幣單位且為整型類型進行存儲。

9. 【強制】浮點數(shù)之間的等值判斷叉谜,基本數(shù)據(jù)類型不能使用 == 進行比較旗吁,包裝數(shù)據(jù)類型不能使用 equals 進行判斷。

說明:浮點數(shù)采用“尾數(shù)+階碼”的編碼方式停局,類似于科學計數(shù)法的“有效數(shù)字+指數(shù)”的表示方式阵漏。二進制無法精確表示大部分的十進制小數(shù),具體原理參考《碼出高效》翻具。
正例: (1)指定一個誤差范圍,兩個浮點數(shù)的差值在此范圍之內回还,則認為是相等的裆泳。

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 來定義值,再進行浮點數(shù)的運算操作柠硕。

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);

if (x.compareTo(y) == 0) {
  System.out.println("true");
}

10. 【強制】BigDecimal 的等值比較應使用 compareTo() 方法工禾,而不是 equals() 方法。

說明:equals() 方法會比較值和精度(1.0 與 1.00 返回結果為 false)蝗柔,而 compareTo() 則會忽略精度闻葵。

11. 【強制】定義數(shù)據(jù)對象 DO 類時,屬性類型要與數(shù)據(jù)庫字段類型相匹配癣丧。

正例:數(shù)據(jù)庫字段的 bigint 必須與類屬性的 Long 類型相對應槽畔。 反例:某業(yè)務的數(shù)據(jù)庫表 id 字段定義類型為 bigint unsigned,實際類對象屬性為 Integer胁编,隨著 id 越來越大厢钧, 超過 Integer 的表示范圍而溢出成為負數(shù),此時數(shù)據(jù)庫 id 不支持存入負數(shù)拋出異常產生線上故障嬉橙。

12.【強制】禁止使用構造方法 BigDecimal(double) 的方式把 double 值轉化為 BigDecimal 對象早直。

說明:BigDecimal(double) 存在精度損失風險,在精確計算或值比較的場景中可能會導致業(yè)務邏輯異常市框。 如: BigDecimal g = new BigDecimal(0.1F)霞扬;實際的存儲值為:0.100000001490116119384765625
正例:優(yōu)先推薦入參為 String 的構造方法,或使用 BigDecimal 的 valueOf 方法枫振,此方法內部其實執(zhí)行了 Double 的 toString喻圃,而 Double 的 toString 按 double 的實際能表達的精度對尾數(shù)進行了截斷。

BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1);

13. 關于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標準如下:
1)【強制】所有的 POJO 類屬性必須使用包裝數(shù)據(jù)類型蒋得。
2)【強制】RPC 方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型级及。
3)【推薦】所有的局部變量使用基本數(shù)據(jù)類型。

說明:POJO 類屬性沒有初值是提醒使用者在需要使用時额衙,必須自己顯式地進行賦值饮焦,任何 NPE 問題怕吴,或者入庫檢查, 都由使用者來保證县踢。
正例:數(shù)據(jù)庫的查詢結果可能是 null转绷,因為自動拆箱,用基本數(shù)據(jù)類型接收有 NPE 風險硼啤。
反例:某業(yè)務的交易報表上顯示成交總額漲跌情況议经,即正負 x%郊尝,x 為基本數(shù)據(jù)類型掘宪,調用的 RPC 服務,調用不成功時道宅, 返回的是默認值嗓袱,頁面顯示為 0%籍救,這是不合理的,應該顯示成中劃線-渠抹。所以包裝數(shù)據(jù)類型的 null 值蝙昙,能夠表示額外的 信息,如:遠程調用失敗梧却,異常退出奇颠。

14. 【強制】定義 DO / PO / DTO / VO 等 POJO 類時,不要設定任何屬性默認值放航。

反例:某業(yè)務的 DO 的 createTime 默認值為 new Date()烈拒;但是這個屬性在數(shù)據(jù)提取時并沒有置入具體值,在更新其它字段時又附帶更新了此字段三椿,導致創(chuàng)建時間被修改成當前時間缺菌。

15.【強制】序列化類新增屬性時,請不要修改 serialVersionUID 字段搜锰,避免反序列失敯橛簟;如果完全不兼容升級蛋叼,避免反序列化混亂焊傅,那么請修改 serialVersionUID 值。
說明:注意 serialVersionUID 不一致會拋出序列化運行時異常狈涮。

16.【強制】構造方法里面禁止加入任何業(yè)務邏輯狐胎,如果有初始化邏輯,請放在 init 方法中歌馍。

17.【強制】POJO 類必須寫 toString 方法握巢。使用 IDE 中的工具 source > generate toString 時,如果繼 承了另一個 POJO 類松却,注意在前面加一下 super.toString()暴浦。

說明:在方法執(zhí)行拋出異常時溅话,可以直接調用 POJO 的 toString() 方法打印其屬性值,便于排查問題歌焦。

18.【強制】禁止在 POJO 類中飞几,同時存在對應屬性 xxx 的 isXxx() 和 getXxx() 方法。

說明:框架在調用屬性 xxx 的提取方法時独撇,并不能確定哪個方法一定是被優(yōu)先調用到屑墨,神坑之一。

19. 【推薦】使用索引訪問用 String 的 split 方法得到的數(shù)組時纷铣,需做最后一個分隔符后有無內容的檢查卵史, 否則會有拋 IndexOutOfBoundsException 的風險。

說明:

String str = "a,b,c,,";
String[] ary = str.split(",");
// 預期大于 3搜立,結果等于 3
System.out.println(ary.length);

20. 【推薦】當一個類有多個構造方法程腹,或者多個同名方法,這些方法應該按順序放置在一起儒拂,便于閱讀, 此條規(guī)則優(yōu)先于下一條色鸳。

正例:

public int method(int param);
protected double method(int param1, int param2);
private void method();

21. 【推薦】類內方法定義的順序依次是:公有方法或保護方法 > 私有方法 > getter / setter 方法社痛。

說明:公有方法是類的調用者和維護者最關心的方法,首屏展示最好命雀;保護方法雖然只是子類關心蒜哀,也可能是“模板設 計模式”下的核心方法;而私有方法外部一般不需要特別關心吏砂,是一個黑盒實現(xiàn)撵儿;因為承載的信息價值較低,所有 Service 和 DAO 的 getter / setter 方法放在類體最后狐血。

22. 【推薦】setter 方法中淀歇,參數(shù)名稱與類成員變量名稱一致,this.成員名=參數(shù)名匈织。在 getter / setter 方法中浪默,不要增加業(yè)務邏輯,增加排查問題的難度缀匕。

反例:

public Integer getData() {
    if (condition) {
        return this.data + 100; 
    } else {
        return this.data - 100;
    }
}

23. 【推薦】循環(huán)體內纳决,字符串的連接方式,使用 StringBuilder 的 append 方法進行擴展乡小。

反例:

String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello";
}

說明:反編譯出的字節(jié)碼文件顯示每次循環(huán)都會 new 出一個 StringBuilder 對象阔加,然后進行 append 操作,最后通過 toString() 返回 String 對象满钟,造成內存資源浪費胜榔。

24. 【推薦】final 可以聲明類胳喷、成員變量、方法苗分、以及本地變量厌蔽,下列情況使用 final 關鍵字:

1)不允許被繼承的類,如:String 類摔癣。
2)不允許修改引用的域對象奴饮,如:POJO 類的域變量。
3)不允許被覆寫的方法择浊,如:POJO 類的 setter 方法戴卜。
4)不允許運行過程中重新賦值的局部變量。
5)避免上下文重復使用一個變量琢岩,使用 final 關鍵字可以強制重新定義一個變量投剥,方便更好地進行重構。

25. 【推薦】慎用 Object 的 clone 方法來拷貝對象担孔。
說明:對象 clone 方法默認是淺拷貝江锨,若想實現(xiàn)深拷貝需覆寫 clone 方法實現(xiàn)域對象的深度遍歷式拷貝。

26. 【推薦】類成員與方法訪問控制從嚴:

1)如果不允許外部直接通過 new 來創(chuàng)建對象糕篇,那么構造方法必須是 private啄育。
2)工具類不允許有 public 或 default 構造方法。
3)類非 static 成員變量并且與子類共享拌消,必須是 protected挑豌。
4)類非 static 成員變量并且僅在本類使用,必須是 private墩崩。
5)類 static 成員變量如果僅在本類使用氓英,必須是 private。
6)若是 static 成員變量鹦筹,考慮是否為 final铝阐。
7)類成員方法只供類內部調用,必須是 private铐拐。
8)類成員方法只對繼承類公開饰迹,那么限制為 protected。 說明:任何類余舶、方法啊鸭、參數(shù)、變量匿值,嚴控訪問范圍赠制。過于寬泛的訪問范圍,不利于模塊解耦。思考:如果是一個 private 的方法钟些,想刪除就刪除烟号,可是一個 public 的 service 成員方法或成員變量,刪除一下政恍,不得手心冒點汗嗎汪拥? 變量像自己的小孩,盡量在自己的視線內篙耗,變量作用域太大迫筑,無限制的到處跑,那么你會擔心的宗弯。

補充知識

六大設計原則解讀

  1. 單一職責原則(Single Responsibility Principle)脯燃,簡稱是 SRP
    SRP 的原話解釋是:
    There should never be more than one reason for a class to change.

應該有且僅有一個原因引起類的變更。

2. 里氏替換原則(Liskov Substitution Principle)
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
所有引用基類的地方必須能透明地使用其子類的對象蒙保。

  1. 子類必須完全實現(xiàn)父類的方法
  2. 子類可以有自己的個性
  3. 覆蓋或實現(xiàn)父類的方法時輸入參數(shù)可以被放大
  4. 覆寫或實現(xiàn)父類的方法時輸出結果可以被縮小

目的: 增強程序的健壯性辕棚,版本升級時也可以保持非常好的兼容性。即使增加子類邓厕,原有的子類還可以繼續(xù)運行逝嚎。在實際項目中,每個子類對應不同的業(yè)務含義详恼,使用父類作為參數(shù)懈糯,傳遞不同的子類完成不同的業(yè)務邏輯,非常完美单雾!

3. 依賴倒置原則(Dependence Inversion Principle)
原始定義:
High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

翻譯過來,包含三層含義:
? 高層模塊不應該依賴低層模塊她紫,兩者都應該依賴其抽象硅堆;
? 抽象不應該依賴細節(jié);
? 細節(jié)應該依賴抽象贿讹。

依賴倒置原則是6個設計原則中最難以實現(xiàn)的原則渐逃,它是實現(xiàn)開閉原則的重要途徑,依賴倒置原則沒有實現(xiàn)民褂,就別想實現(xiàn)對擴展開放茄菊,對修改關閉。在項目中赊堪,大家只要記住是“面向接口編程”就基本上抓住了依賴倒置原則的核心面殖。

4. 接口隔離原則(Interface Segregation Principle)
它有兩種定義,如下所示:
?Clients should not be forced to depend upon interfaces that they don't use.(客戶端不應該依賴它不需要的接口哭廉。)
?The dependency of one class to another one should depend on the smallest possible interface.(類間的依賴關系應該建立在最小的接口上脊僚。)

新事物的定義一般都比較難理解,晦澀難懂是正常的遵绰。我們把這兩個定義剖析一下辽幌,先說第一種定義:“客戶端不應該依賴它不需要的接口”增淹,那依賴什么?依賴它需要的接口乌企,客戶端需要什么接口就提供什么接口虑润,把不需要的接口剔除掉,那就需要對接口進行細化加酵,保證其純潔性拳喻;再看第二種定義:“類間的依賴關系應該建立在最小的接口上”,它要求是最小的接口虽画,也是要求接口細化舞蔽,接口純潔,與第一個定義如出一轍码撰,只是一個事物的兩種不同描述渗柿。

5. 迪米特法則(Law of Demeter)
迪米特法則(Law of Demeter,LoD)也稱為最少知識原則(Least Knowledge Principle,LKP),雖然名字不同脖岛,但描述的是同一個規(guī)則:一個對象應該對其他對象有最少的了解朵栖。

通俗地講,一個類應該對自己需要耦合或調用的類知道得最少柴梆,你(被耦合或調用的類)的內部是如何復雜都和我沒關系陨溅,那是你的事情,我就知道你提供的這么多public方法绍在,我就調用這么多门扇,其他的我一概不關心。

迪米特法則的核心觀念就是類間解耦偿渡,弱耦合臼寄,只有弱耦合了以后,類的復用率才可以提高溜宽。其要求的結果就是產生了大量的中轉或跳轉類吉拳,導致系統(tǒng)的復雜性提高,同時也為維護帶來了難度适揉。讀者在采用迪米特法則時需要反復權衡留攒,既做到讓結構清晰,又做到高內聚低耦合嫉嘀。

6. 開閉原則(Open Closed Principle)

Software entities like classes,modules and functions should be open for extension but closed for modifications.(一個軟件實體如類炼邀、模塊和函數(shù)應該對擴展開放,對修改關閉剪侮。)

開閉原則告訴我們應盡量通過擴展軟件實體的行為來實現(xiàn)變化汤善,而不是通過修改已有的代碼來完成變化,它是為軟件實體的未來事件而制定的對現(xiàn)行開發(fā)設計進行約束的一個原則。

把這6個原則的首字母(里氏替換原則和迪米特法則的首字母重復红淡,只取一個)聯(lián)合起來就是SOLID(solid不狮,穩(wěn)定的),其代表的含義也就是把這6個原則結合使用的好處:建立穩(wěn)定在旱、靈活摇零、健壯的設計,而開閉原則又是重中之重桶蝎,是最基礎的原則驻仅,是其他5大原則的精神領袖

參考(References)

  • 《1. 2022 Java開發(fā)手冊(黃山版).pdf
  • 《設計模式之禪 第1版》
  • 《Java技術手冊 第6版》
  • 《編寫高質量代碼:改善Java程序的151個建議》
  • 白話阿里巴巴Java開發(fā)手冊(安全規(guī)約) - 李艷鵬 - 簡書(http://www.reibang.com/p/9528c4ea1504)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末登渣,一起剝皮案震驚了整個濱河市噪服,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胜茧,老刑警劉巖粘优,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異呻顽,居然都是意外死亡雹顺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門廊遍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嬉愧,“玉大人,你說我怎么就攤上這事喉前∶缓ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵卵迂,是天一觀的道長裕便。 經常有香客問我,道長狭握,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任疯溺,我火速辦了婚禮论颅,結果婚禮上,老公的妹妹穿的比我還像新娘囱嫩。我一直安慰自己恃疯,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布墨闲。 她就那樣靜靜地躺著今妄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盾鳞,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天犬性,我揣著相機與錄音,去河邊找鬼腾仅。 笑死乒裆,一個胖子當著我的面吹牛,可吹牛的內容都是我干的推励。 我是一名探鬼主播鹤耍,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼验辞!你這毒婦竟也來了稿黄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤跌造,失蹤者是張志新(化名)和其女友劉穎杆怕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鼻听,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡财著,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了撑碴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撑教。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖醉拓,靈堂內的尸體忽然破棺而出伟姐,到底是詐尸還是另有隱情,我是刑警寧澤亿卤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布愤兵,位于F島的核電站,受9級特大地震影響排吴,放射性物質發(fā)生泄漏秆乳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一钻哩、第九天 我趴在偏房一處隱蔽的房頂上張望屹堰。 院中可真熱鬧,春花似錦街氢、人聲如沸扯键。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荣刑。三九已至馅笙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厉亏,已是汗流浹背董习。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叶堆,地道東北人阱飘。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像虱颗,于是被迫代替她去往敵國和親沥匈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理忘渔,服務發(fā)現(xiàn)高帖,斷路器,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 來源與:阿里云棲 禁止用于商業(yè)用途 ps:如果需要電子書 評論你們郵箱 我會發(fā)給你們 下面感覺還是有點亂 目錄 一...
    小向資源網閱讀 7,586評論 0 12
  • 傳送門 解讀阿里Java開發(fā)手冊(v1.1.1) - 異常日志 前言 阿里Java開發(fā)手冊談不上圣經畦粮,但確實是大量...
    kelgon閱讀 4,366評論 4 50
  • 你不來 不聞不問
    HS安林閱讀 149評論 0 0
  • 天實在太熱了散址,熱得二百多斤的凱哥又起了痱子,下班回來一動不動地開著空調看手機宣赔,我覺得讓他保持這個姿勢预麸,他可以連飯都...
    玲玲筱雪閱讀 150評論 0 0