講稿2019阿里編程_第1頁
講稿2019阿里編程_第2頁
講稿2019阿里編程_第3頁
講稿2019阿里編程_第4頁
講稿2019阿里編程_第5頁
已閱讀5頁,還剩42頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、前 言技術(shù)團(tuán)隊(duì)的集體智慧結(jié)晶和經(jīng)驗(yàn)總結(jié),經(jīng)歷了多次大規(guī)模Java 開發(fā)手冊(cè)是阿里巴巴一線實(shí)戰(zhàn)的檢驗(yàn)及不斷完善,公開到業(yè)界后,眾多社區(qū)開發(fā)者踴躍參與,共同打磨完善,系統(tǒng)化地整理成冊(cè)?,F(xiàn)代軟件行業(yè)的高速發(fā)展對(duì)開發(fā)者的綜合素質(zhì)要求越來越高,因?yàn)椴粌H是編程知識(shí)點(diǎn), 其它維度的知識(shí)點(diǎn)也會(huì)影響到軟件的最終交付質(zhì)量。比如:數(shù)據(jù)庫的表結(jié)構(gòu)和索引設(shè)計(jì)缺陷可能帶來軟件上的架構(gòu)缺陷或性能風(fēng)險(xiǎn);工程結(jié)構(gòu)導(dǎo)致后續(xù)維護(hù)艱難;沒有鑒權(quán)的漏洞代碼易被等等。所以本手冊(cè)以 Java 開發(fā)者為中心視角,劃分為編程規(guī)約、異常日志、單元測(cè)試、安全規(guī)約、MySQL 數(shù)據(jù)庫、工程結(jié)構(gòu)、設(shè)計(jì)規(guī)約七個(gè)維度,再根據(jù)內(nèi)容特征,細(xì)分成若干子目錄。另

2、外,依據(jù)約束力強(qiáng)弱及故障敏感性,規(guī)約依次分為強(qiáng)制、推薦、參考三大類。在延伸信息中,“說明”對(duì)規(guī)約做了適當(dāng)擴(kuò)展和解釋;“正例”提倡什么樣的編碼和實(shí)現(xiàn)方式;“反例”說明需要提防的雷區(qū),以及真實(shí)的錯(cuò)誤案例。手冊(cè)的愿景是碼出高效,碼出質(zhì)量。現(xiàn)代軟件架構(gòu)的復(fù)雜性需要協(xié)同開發(fā)完成,如何高效地協(xié)同呢?無規(guī)矩不成方圓,無規(guī)范難以協(xié)同,比如,制訂交通表面上是要限制行車權(quán),實(shí)際上是保障公眾的人身安全,試想如果沒有限速,沒有紅綠燈,誰還敢上路行駛?對(duì)軟件來說,適當(dāng)?shù)囊?guī)標(biāo)準(zhǔn)絕不是消滅代碼內(nèi)容的創(chuàng)造性、優(yōu)雅性,而是限制過度個(gè)性化,以一種普遍認(rèn)可的統(tǒng)一方式一起做事,提升協(xié)作效率,降低成本。代碼的字里行間流淌的是軟件系統(tǒng)的

3、血液,質(zhì)量的提升是盡可能少踩坑,杜絕踩重復(fù)的坑,切實(shí)提升系統(tǒng)穩(wěn)定性,碼出質(zhì)量。我們已經(jīng)在 2017 杭州云棲大會(huì)上發(fā)布了配套的 Java 開發(fā)規(guī)約 IDE 插件,效也集成了代碼規(guī)約掃描引擎。次年,發(fā)布 36的配套詳解碼出高效,本書秉持“圖勝于表,于言”的理念,深入淺出地將計(jì)算機(jī)基礎(chǔ)、面向?qū)ο笏枷?、JVM 探源、數(shù)據(jù)結(jié)構(gòu)與集合、并發(fā)與多線程、單元測(cè)試等知識(shí)客觀、地呈現(xiàn)出來。緊扣、精進(jìn)的目標(biāo),結(jié)合阿里巴巴實(shí)踐經(jīng)驗(yàn)和故障案例,與底層源碼融會(huì)貫通,娓娓道來。此書所得收入均捐贈(zèng)公益事情,希望用技術(shù)情懷幫助的人。目錄(一)(二)(三)(四)(五)(六)(七)(八)(九)命名風(fēng)格1定義4代碼格式5OOP 規(guī)

4、約7集合處理11并發(fā)處理14語句18注釋規(guī)約21其它22二、異常日志24(一)(二)異常處理24日志規(guī)約26(一)(二)(三)(四)建表規(guī)約31索引規(guī)約32SQL 語句34ORM.35六、工程結(jié)構(gòu)37(一)(二)(三)應(yīng)用分層37二方庫依賴38服務(wù)器39(注:瀏覽時(shí)請(qǐng)使用 PDF 左側(cè)導(dǎo)航欄)七、設(shè)計(jì)規(guī)約41附 1:版本歷史43附 2:專有名詞解釋44三、單元測(cè)試28四、安全規(guī)約30五、MySQL 數(shù)據(jù)庫31前言一、編程規(guī)約1Java 開發(fā)手冊(cè)一、 編程規(guī)約(一)1.命名風(fēng)格【強(qiáng)制】代碼中名均不能以下劃線或符號(hào)開始,也不能以下劃線或符號(hào)結(jié)束。反例:_name / name / $name /

5、name_ / name$ / name 2.【強(qiáng)制】代碼中名嚴(yán)禁使用拼音與英文混合的方式,更不直接使用中文的方式。說明:正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。注意,純拼音命名方式更要避免采用。正例:renminbi / alibaba / youku / hangzhou 等國際通用的名稱,可視同英文。反例:DaZhePromotion 打折 / getPingfenByName() 評(píng)分 / int 某變量 = 33.【強(qiáng)制】類名使用 UpperCamelCase 風(fēng)格,但以下情形例外:DO / BO / DTO / VO / AO/ PO / UID 等。正例:JavaSe

6、rverlessPlatform / UserDO / XmlService / TcpUdpDeal / TaPromotion反例:javaserverlessplatform / UserDo / XMLService / TCPUDPDeal / TAPromotion4.【強(qiáng)制】方法名、參數(shù)名、成員變量、局部變量都統(tǒng)一使用 lowerCamelCase 風(fēng)格,必須遵從駝峰形式。正例: localValue / getHttpMessage() / inputUserId5.【強(qiáng)制】長。命名全部大寫,單詞間用下劃線隔開,力求語義表達(dá)完整清楚,不要嫌名字正例:MAX_STOCK_COUN

7、T / CACHE_EXPIRED_TIME反例:MAX_COUNT / EXPIRED_TIME6.【強(qiáng)制】抽象類命名使用 Abstract 或 Base 開頭;異常類命名使用 Exception 結(jié)尾;測(cè)試類命名以它要測(cè)試的類的名稱開始,以 Test 結(jié)尾。【強(qiáng)制】類型與中括號(hào)緊挨相連來表示數(shù)組。正例:定義整形數(shù)組 int arrayDemo;反例:在 main 參數(shù)中,使用 String args來定義。7.8.【強(qiáng)制】POJO 類中類型變量都不要加 is 前綴,否則部分框架會(huì)引起序列化錯(cuò)誤。名方式,所以,需要在說明:在本文 MySQL 規(guī)約中的建表約定第一條,表達(dá)是與否的值采用 is_

8、<resultMap>設(shè)置從 is_到的關(guān)系。反例:定義為基本數(shù)據(jù)類型 Boolean isDeleted 的屬性,它的方法也是 isDeleted(),RPC 框架在反向解析的時(shí)候,“誤以為”對(duì)應(yīng)的屬性名稱是 deleted,導(dǎo)致屬性獲取不到,進(jìn)而拋出異常。1/44版本號(hào)制定團(tuán)隊(duì)更新日期備注1.5.0阿里巴巴與 Java 社區(qū)開發(fā)者2019.06.19華山版,新增 21 條,修改描述 112 處Java 開發(fā)手冊(cè)9. 【強(qiáng)制】統(tǒng)一使用小寫,點(diǎn)分隔符之間有且僅有一個(gè)自然語義的英語單詞。統(tǒng)一使用單數(shù)形式,但是類名如果有復(fù)數(shù)含義,類名可以使用復(fù)數(shù)形式。正例:應(yīng)用工具類為 com.ali

9、baba.ai.util、類名為 MessageUtils(此規(guī)則參考 spring 的框架結(jié)構(gòu))10. 【強(qiáng)制】避免在子父類的成員變量之間、或者不同代碼塊的局部變量之間采用完全相同名,使可讀性降低。說明:子類、父類成員變量名相同,即使是 public 類型的變量也是能夠通過編譯,而局部變量在同一方法內(nèi)的不同代碼塊中同名也是合法的,但是要避免使用。對(duì)于非 setter/getter 的參數(shù)名稱也要避免與成員變量名稱相同。反例:public class ConfusingName public int age;/ 非 setter/getter 的參數(shù)名稱,不public void getDat

10、a(String alibaba) if(condition) final int money = 531;/ .與本類成員變量同名for (int i = 0; i < 10; i+) / 在同一方法體中,不與其它代碼塊中的 money 命名相同final int money = 615;/ .class Son extends ConfusingName / 不與父類的成員變量名稱相同public int age;11. 【強(qiáng)制】杜絕完全不規(guī)范的縮寫,避免不知義。反例:AbstractClass“縮寫”命名成 AbsClass;condition“縮寫”命名成降低了代碼的可閱讀性。c

11、ondi,此類隨意縮寫嚴(yán)重12. 【推薦】為了達(dá)到代碼自解釋的目標(biāo),任何自定義編程元素在命名時(shí),使用盡量完整的單詞組合來表達(dá)其意。正例:在 JDK 中,表達(dá)原子更新的類名為:AtomicReferenceFieldUpdater。反例:int a 的隨意命名方式。13. 【推薦】在與變量名時(shí),表示類型的名詞放在詞尾,以提升辨識(shí)度。正例:startTime / workQueue / nameList / TERMINATED_THREAD_COUNT反例:startedAt / QueueOfWork / listName / COUNT_TERMINATED_THREAD14. 【推薦】如果

12、模塊、接口、類、方法使用了設(shè)計(jì)模式,在命名體現(xiàn)出具體模式。說明:將設(shè)計(jì)模式體現(xiàn)在名字中,有利于閱讀者快速理解架構(gòu)設(shè)計(jì)理念。2/44Java 開發(fā)手冊(cè)正例: public class OrderFactory;public class LoginProxy;public class ResourceObserver;15. 【推薦】接口類中的方法和屬性不要加任何修飾符號(hào)(public 也不要加),保持代碼的簡潔性,并加上有效的 Javadoc 注釋。盡量不要在接口里定義變量,如果一定要定義變量,肯定是與接口方法相關(guān),并且是整個(gè)應(yīng)用的基礎(chǔ)。正例:接口方法簽名接口基礎(chǔ)反例:接口方法定義說明:JDK8

13、 中接口void commit();String COMPANY = "alibaba" public abstract void f();有默認(rèn)實(shí)現(xiàn),那么這個(gè) default 方法,是對(duì)所有實(shí)現(xiàn)類都有價(jià)值的默認(rèn)實(shí)現(xiàn)。16. 接口和實(shí)現(xiàn)類名有兩套規(guī)則:1)【強(qiáng)制】對(duì)于 Service 和 DAO 類,基于 SOA 的理念,Impl 的后綴與接口區(qū)別。正例:CacheServiceImpl 實(shí)現(xiàn) CacheService 接口。出來的服務(wù)一定是接口,內(nèi)部的實(shí)現(xiàn)類用2) 【推薦】如果是形容能力的接口名稱,取對(duì)應(yīng)的形容詞為接口名(通常是able 的形容詞)。正例:Abstract

14、Translator 實(shí)現(xiàn) Translatable 接口。17. 【參考】枚舉類名帶上 Enum 后綴,枚舉成員名稱需要寫,單詞間用下劃線隔開。說明:枚舉其實(shí)就是特殊的類,域成員均為,且構(gòu)造方法被默認(rèn)強(qiáng)制是私有。正例:枚舉名字為 ProcessStatusEnum 的成員名稱:SUCCESS / UNKNOWN_REASON。18. 【參考】各層命名規(guī)約:A) Service/DAO 層方法命名規(guī)約1)2)3)4)5)6)獲取單個(gè)對(duì)象的方法用 get 做前綴。獲取多個(gè)對(duì)象的方法用 list 做前綴,復(fù)數(shù)形式結(jié)尾如:listObjects。獲取統(tǒng)計(jì)值的方法用 count 做前綴。的方法用 sa

15、ve/insert 做前綴。刪除的方法用 remove/delete 做前綴。修改的方法用 update 做前綴。B)領(lǐng)域模型命名規(guī)約1)2)3)4)數(shù)據(jù)對(duì)象:DO,即為數(shù)據(jù)表名。數(shù)據(jù)傳輸對(duì)象:DTO,為業(yè)務(wù)領(lǐng)域相關(guān)的名稱。展示對(duì)象:VO,一般為網(wǎng)頁名稱。POJO 是 DO/DTO/BO/VO 的統(tǒng)稱,命名成POJO。3/44Java 開發(fā)手冊(cè)(二)1.定義【強(qiáng)制】不任何魔法值(即預(yù)先定義的)直接出現(xiàn)在代碼中。反例:String key = "Id#_" + tradeId;cache.put(key, value);/ 緩存 get 時(shí),由于在代碼時(shí),漏掉下劃線,導(dǎo)致緩存

16、擊穿而出現(xiàn)問題2.【強(qiáng)制】在 long 或者Long 賦值時(shí),數(shù)值后使用大寫的 L,不能是小寫的 l,小寫容易跟數(shù)字 1,造成誤解。說明:Long a = 2l; 寫的是數(shù)字的 21,還是Long 型的 2。3.【推薦】不要使用一個(gè)類維護(hù)所有,要按功能進(jìn)行歸類,維護(hù)。說明:大而全的正例:緩存相關(guān)類,雜亂無章,使用查找功能才能到修改的,不利于理解和維護(hù)。放在類 CacheConsts 下;系統(tǒng)配置相關(guān)放在類 ConfigConsts 下。4.【推薦】包內(nèi)共享的復(fù)用層次有五層:跨應(yīng)用共享、應(yīng)用內(nèi)共享、子工程內(nèi)共享、類內(nèi)共享。1) 跨應(yīng)用共享2) 應(yīng)用內(nèi)共享:放置在二方庫中,通常是 client.j

17、ar 中的 constant 目錄下。:放置在一方庫中,通常是子模塊中的 constant 目錄下。反例:易懂變量也要統(tǒng)一定義成應(yīng)用內(nèi)共享,兩位工程師在兩個(gè)類中分別定義了“YES”的變量:類 A 中:public static final String YES = "yes"類 B 中:public static final String YES = "y"A.YES.equals(B.YES),預(yù)期是 true,但實(shí)際返回為 false,導(dǎo)致線上問題。3)4)5)子工程內(nèi)部共享:即在當(dāng)前子工程的 constant 目錄下。包內(nèi)共享類內(nèi)共享:即在當(dāng)前包下

18、單獨(dú)的 constant 目錄下。:直接在類內(nèi)部 private static final 定義。5.【推薦】如果變量值僅在一個(gè)固定范圍內(nèi)變化用 enum 類型來定義。說明:如果名稱之外的延伸屬性應(yīng)使用 enum 類型,下面正例中的數(shù)字就是延伸信息,表示一年中的第幾個(gè)季節(jié)。正例:public enum SeasonEnum SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);private int seq; SeasonEnum(int seq) this.seq = seq;public int getSeq() return seq;4/44Java 開發(fā)

19、手冊(cè)(三)1.代碼格式【強(qiáng)制】如果是大括號(hào)內(nèi)為空,則簡潔地寫成即可,大括號(hào)中間無需換行和空格;如果是非空代碼塊則:1)2)3)4)左大括號(hào)前不換行。左大括號(hào)后換行。右大括號(hào)前換行。右大括號(hào)后還有 else 等代碼則不換行;表示終止的右大括號(hào)后必須換行。2.【強(qiáng)制】左小括號(hào)和字符之間不出現(xiàn)空格;同樣,右小括號(hào)和字符之間也不出現(xiàn)空格;而左大括號(hào)前需要空格。詳見第 5 條下方正例提示。反例:if (空格 a = b 空格)3.4.【強(qiáng)制】if/for/while/switch/do 等保留字與括號(hào)之間都必須加空格?!緩?qiáng)制】任何二目、三目運(yùn)算符的左右兩邊都需要加一個(gè)空格。說明:運(yùn)算符包括賦值運(yùn)算符=、

20、邏輯運(yùn)算符&&、加減乘除符號(hào)等。5.【強(qiáng)制】采用 4 個(gè)空格縮進(jìn),使用 tab 字符。說明:如果使用 tab 縮進(jìn),必須設(shè)置 1 個(gè)tab 為 4 個(gè)空格。IDEA 設(shè)置 tab 為 4 個(gè)空格時(shí),tab character;而在 eclipse 中,必須勾選 insert spaces for tabs。正例: (涉及 1-5 點(diǎn))勾選 Usepublic static void main(String args) / 縮進(jìn) 4 個(gè)空格String say = "hello"/ 運(yùn)算符的左右必須有一個(gè)空格int flag = 0;/if 與括號(hào)之間必須有一

21、個(gè)空格,括號(hào)內(nèi)的 f 與左括號(hào),0 與右括號(hào)不需要空格if (flag = 0) System.out.println(say);/ 左大括號(hào)前加空格且不換行;左大括號(hào)后換行if (flag = 1) System.out.println("world");/ 右大括號(hào)前換行,右大括號(hào)后有 else,不用換行 else System.out.println("ok");/ 在右大括號(hào)后直接結(jié)束,則必須換行6.【強(qiáng)制】注釋的雙斜線與注釋內(nèi)容之間有且僅有一個(gè)空格。正例:/ 這是示例注釋,請(qǐng)注意在雙斜線之后有一個(gè)空格String param = new Str

22、ing();5/44Java 開發(fā)手冊(cè)7.【強(qiáng)制】在進(jìn)行類型強(qiáng)制轉(zhuǎn)換時(shí),右括號(hào)與強(qiáng)制轉(zhuǎn)換值之間不需要任何空格隔開。正例:long first = 1000000000000L; int second = (int)first + 2;【強(qiáng)制】單行字符數(shù)限制不超過 120 個(gè),超出需要換行,換行時(shí)遵循如下原則:1) 第二行相對(duì)第一行縮進(jìn) 4 個(gè)空格,從第三行開始,不再繼續(xù)縮進(jìn),參考示例。2) 運(yùn)算符與下文一起換行。3) 方法調(diào)用的點(diǎn)符號(hào)與下文一起換行。4) 方法調(diào)用中的多個(gè)參數(shù)需要換行時(shí),在逗號(hào)后進(jìn)行。5) 在括號(hào)前不要換行,見反例。正例:StringBuilder sb = new Strin

23、gBuilder();8./ 超過 120 個(gè)字符的情,換行縮進(jìn) 4 個(gè)空格,點(diǎn)號(hào)和方法名稱一起換行sb.append("Jack").append("Ma").append("alibaba").append("alibaba").append("alibaba");反例:StringBuilder sb = new StringBuilder();/ 超過 120 個(gè)字符的情,不要在括號(hào)前換行sb.append("Jack").append("Ma")

24、.append ("alibaba");/ 參數(shù)很多的方法調(diào)用可能超過 120 個(gè)字符,不要在逗號(hào)前換行method(args1, args2, args3, ., argsX);9.【強(qiáng)制】方法參數(shù)在傳入時(shí),多個(gè)參數(shù)逗號(hào)后邊必須加空格。正例:下例中實(shí)參的 args1,后邊必須要有一個(gè)空格。method(args1, args2, args3);10. 【強(qiáng)制】IDE 的 text file encoding 設(shè)置為 UTF-8; IDE 中文件的換行符使用 Unix 格式,不要使用 Windows 格式。11. 【推薦】單個(gè)方法的總行數(shù)不超過 80 行。說明:除注釋之外的

25、方法簽名、左右大括號(hào)、方法內(nèi)代碼、空行、回車及任何不可見字符的總行數(shù)不超過80 行。正例:代碼邏輯分清紅花和綠葉,個(gè)性和共性,綠葉邏輯單獨(dú)出來成為額外方法,使共性邏輯抽取成為共性方法,便于復(fù)用和維護(hù)。碼更加清晰;12. 【推薦】沒有必要增加若干空格來使變量的賦值等號(hào)與上一行對(duì)應(yīng)位置的等號(hào)對(duì)齊。正例:int one = 1; long two = 2L; float three = 3F;StringBuilder sb = new StringBuilder();6/44Java 開發(fā)手冊(cè)說明:增加 sb 這個(gè)變量,如果需要對(duì)齊,則給one、two、three 都要增加幾個(gè)空格,在變量比較多的

26、情,是非常累贅的事情。13. 【推薦】不同邏輯、不同語義、不同業(yè)務(wù)的代碼之間一個(gè)空行分隔開來以提升可讀性。說明:任何情形,沒有必要多個(gè)空行進(jìn)行隔開。(四)1.OOP 規(guī)約【強(qiáng)制】避免通過一個(gè)類的對(duì)象此類的靜態(tài)變量或靜態(tài)方法,無謂增加編譯器成本,直接用類名來即可。2.【強(qiáng)制】所有的覆寫方法,必須加Override 注解。說明:getObject()與 get0bject()的問題。一個(gè)是字母的 O,一個(gè)是數(shù)字的 0,加Override 可以準(zhǔn)確判斷是否覆蓋。另外,如果在抽象類中對(duì)方法簽名進(jìn)行修改,其實(shí)現(xiàn)類會(huì)馬上編譯報(bào)錯(cuò)。3.【強(qiáng)制】相同參數(shù)類型,相同業(yè)務(wù)含義,才可以使用 Java 的可變參數(shù),避

27、免使用 Object。說明:可變參數(shù)必須放置在參數(shù)列表的最后。(提倡同學(xué)們盡量不用可變參數(shù)編程)正例:public List<User> listUsers(String type, Long. ids) .4.【強(qiáng)制】外部正在調(diào)用或者二方庫依賴的接口,不修改方法簽名,避免對(duì)接口調(diào)用方產(chǎn)生影響。接口過時(shí)必須加Deprecated 注解,并清晰地說明采用的新接口或者新服務(wù)是什么?!緩?qiáng)制】不能使用過時(shí)的類或方法。5.說明:.URLDecoder 中的方法 decode(String encodeStr) 這個(gè)方法已經(jīng)過時(shí),應(yīng)該使參數(shù)decode(String source, Strin

28、g encode)。接口提供方既然明確是過時(shí)接口,那么有義務(wù)同時(shí)提供新的接口;作為調(diào)用方來說,有義務(wù)去考證過時(shí)方法的新實(shí)現(xiàn)是什么。6.【強(qiáng)制】Object 的 equals 方法容易拋空指針異常,應(yīng)使用或確定有值的對(duì)象來調(diào)用equals。正例:"test".equals(object); 反例:object.equals("test");說明:推薦使用 java.util.Objects#equals(JDK7 引入的工具類)。7.【強(qiáng)制】所有整型包裝類對(duì)象之間值的比較,全部使用 equals 方法比較。說明:對(duì)于 Integer var = ? 在-1

29、28 至 127 范圍內(nèi)的賦值,Integer 對(duì)象是在 IntegerCache.cache 產(chǎn)生,會(huì)復(fù)用已有對(duì)象,這個(gè)區(qū)間內(nèi)的 Integer 值可以直接使用=進(jìn)行,但是這個(gè)區(qū)間之外的所有數(shù)據(jù),都會(huì)在堆上產(chǎn)生,并復(fù)用已有對(duì)象,這是一個(gè)大坑,推薦使用 equals 方法進(jìn)行。8.【強(qiáng)制】浮點(diǎn)數(shù)之間的等值,基本數(shù)據(jù)類型不能用=來比較,包裝數(shù)據(jù)類型不能用equals 來。說明:浮點(diǎn)數(shù)采用“尾數(shù)+階碼”的編碼方式,類似于科學(xué)計(jì)數(shù)法的“有效數(shù)字+指數(shù)”的表示方式。二進(jìn)7/44Java 開發(fā)手冊(cè)制無法精確表示大部分的十進(jìn)制小數(shù),具體原理參考碼出高效。反例:float a = 1.0f - 0.9f;

30、float b = 0.9f - 0.8f;if (a = b) / 預(yù)期進(jìn)入此代碼快,執(zhí)行其它業(yè)務(wù)邏輯/ 但事實(shí)上 a=b 的結(jié)果為falseFloat x = Float.valueOf(a); Float y = Float.valueOf(b); if (x.equals(y) / 預(yù)期進(jìn)入此代碼快,執(zhí)行其它業(yè)務(wù)邏輯/ 但事實(shí)上 equals 的結(jié)果為false正例:(1) 指定一個(gè)誤差范圍,兩個(gè)浮點(diǎn)數(shù)的差值在此范圍之內(nèi),則認(rèn)為是相等的。float a = 1.0f - 0.9f; float b = 0.9f - 0.8f; float diff = 1e-6f;if (Math.a

31、bs(a - b) < diff) System.out.println("true");(2) 使用 BigDecimal 來定義值,再進(jìn)行浮點(diǎn)數(shù)的運(yùn)算操作。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

32、.equals(y) System.out.println("true");9. 【強(qiáng)制】定義數(shù)據(jù)對(duì)象 DO 類時(shí),屬性類型要與數(shù)據(jù)庫字段類型相匹配。正例:數(shù)據(jù)庫字段的 bigint 必須與類屬性的 Long 類型相對(duì)應(yīng)。反例:某個(gè)案例的數(shù)據(jù)庫表 id 字段定義類型bigint unsigned,實(shí)際類對(duì)象屬性為 Integer,隨著 id 越來越大,超過 Integer 的表示范圍而溢出成為負(fù)數(shù)。10. 【強(qiáng)制】為了防止精度損失,化為 BigDecimal 對(duì)象。使用構(gòu)造方法 BigDecimal(double)的方式把 double 值轉(zhuǎn)說明:BigDecimal(do

33、uble)精度損失風(fēng)險(xiǎn),在精確計(jì)算或值比較的場(chǎng)景中可能會(huì)導(dǎo)致業(yè)務(wù)邏輯異常。如:BigDecimal g = new BigDecimal(0.1f); 實(shí)際的值為:0.10000000149正例:優(yōu)先推薦入?yún)?String 的構(gòu)造方法,或使用 BigDecimal 的 valueOf 方法,此方法內(nèi)部其實(shí)執(zhí)行了Double 的 toString,而 Double 的toString 按 double 的實(shí)際能表達(dá)的精度對(duì)尾數(shù)進(jìn)行了截?cái)唷?/44Java 開發(fā)手冊(cè)BigDecimal recommend1 = new BigDecimal("0.1"); BigDecima

34、l recommend2 = BigDecimal.valueOf(0.1);11. 關(guān)于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標(biāo)準(zhǔn)如下:1)2)3)【強(qiáng)制】所有的 POJO 類屬性必須使用包裝數(shù)據(jù)類型。【強(qiáng)制】RPC 方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型。【推薦】所有的局部變量使用基本數(shù)據(jù)類型。說明:POJO 類屬性沒有初值是提醒使用者在需要使用時(shí),必須者入庫檢查,使用者來保證。顯式地進(jìn)行賦值,任何 NPE 問題,或正例:數(shù)據(jù)庫的結(jié)果可能是 null,因?yàn)樽詣?dòng)拆箱,用基本數(shù)據(jù)類型接收有 NPE 風(fēng)險(xiǎn)。反例:比如顯示成交總額漲跌情況,即正負(fù) x%,x 為基本數(shù)據(jù)類型,調(diào)用的 RPC 服務(wù),調(diào)用不時(shí)

35、,返回的是默認(rèn)值,頁面顯示為 0%,這是不合理的,應(yīng)該顯示劃線。所以包裝數(shù)據(jù)類型的 null 值,能夠表示額外的信息,如:調(diào)用失敗,異常。12. 【強(qiáng)制】定義 DO/DTO/VO 等 POJO 類時(shí),不要設(shè)定任何屬性默認(rèn)值。反例:POJO 類的 createTime 默認(rèn)值為 new Date(),但是這個(gè)屬性在數(shù)據(jù)提取更新其它字段時(shí)又附帶更新了此字段,導(dǎo)致創(chuàng)建時(shí)間被修改成當(dāng)前時(shí)間。沒有置入具體值,在13. 【強(qiáng)制】序列化類新增屬性時(shí),請(qǐng)不要修改 serialVersionUID 字段,避免反序列失??;如果完全不兼容升級(jí),避免反序列化,那么請(qǐng)修改 serialVersionUID 值。說明:注

36、意 serialVersionUID 不一致會(huì)拋出序列化運(yùn)行時(shí)異常。14. 【強(qiáng)制】構(gòu)造方法里面加入任何業(yè)務(wù)邏輯,如果有初始化邏輯,請(qǐng)放在 init 方法中。15. 【強(qiáng)制】POJO 類必須寫 toString 方法。使用 IDE 中的工具:source> generate toString時(shí),如果繼承了另一個(gè) POJO 類,注意在前面加一下 super.toString。說明:在方法執(zhí)行拋出異常時(shí),可以直接調(diào)用 POJO 的 toString()方法打印其屬性值,便于排查問題。16. 【強(qiáng)制】在 POJO 類中,同時(shí)對(duì)應(yīng)屬性的 is()和 get()方法。說明:框架在調(diào)用屬性的提取方法

37、不能確定哪個(gè)方法一定是被優(yōu)先調(diào)用到。17. 【推薦】使用索引用 String 的 split 方法得到的數(shù)組做最后一個(gè)分隔符后有無內(nèi)容的檢查,否則會(huì)有拋 IndexOutOfBoundsException 的風(fēng)險(xiǎn)。說明:String str = "a,b,c,"String ary = str.split(",");/ 預(yù)期大于 3,結(jié)果是 3 System.out.println(ary.length);18. 【推薦】當(dāng)一個(gè)類有多個(gè)構(gòu)造方法,或者多個(gè)同名方法,這些方法應(yīng)該按順序放置在一起,便于閱讀,此條規(guī)則優(yōu)先于下一條。19. 【推薦】 類內(nèi)方法定義

38、的順序依次是:公有方法或保護(hù)方法 > 私有方法 > getter / setter方法。說明:公有方法是類的調(diào)用者和維護(hù)者最關(guān)心的方法,首屏展示最好;保護(hù)方法雖然只是子類關(guān)心,也可9/44Java 開發(fā)手冊(cè)能是“模板設(shè)計(jì)模式”下的方法;而私有方法外部一般不需要特別關(guān)心,是一個(gè)黑盒實(shí)現(xiàn);因?yàn)槌休d的信息價(jià)值較低,所有 Service 和 DAO 的 getter/setter 方法放在類體最后。20. 【推薦】setter 方法中,參數(shù)名稱與類成員變量名稱一致,this.成員名 = 參數(shù)名。在getter/setter 方法中,不要增加業(yè)務(wù)邏輯,增加排查問題的難度。反例:public

39、Integer getData() if (condition) return this.data + 100; else return this.data - 100;21. 【推薦】循環(huán)體內(nèi),字符串的連接方式,使用 StringBuilder 的 append 方法進(jìn)行擴(kuò)展。說明:下例中,反編譯出的字節(jié)碼文件顯示每次循環(huán)都會(huì) new 出一個(gè) StringBuilder 對(duì)象,然后進(jìn)行append 操作,最后通過 toString 方法返回 String 對(duì)象,造成內(nèi)存反例:String str = "start"for (int i = 0; i < 100; i

40、+) str = str + "hello"浪費(fèi)。22. 【推薦】final 可以類、成員變量、方法、以及本地變量,下列情況使用 final 關(guān)鍵字:1) 不被繼承的類,如:String 類。2)3)4)5)不不不修改的域?qū)ο?。被覆寫的方法,如:POJO 類的 setter 方法。運(yùn)行過程中重新賦值的局部變量。避免上下文重復(fù)使用一個(gè)變量,使用 final 可以強(qiáng)制重新定義一個(gè)變量,方便更好地進(jìn)行重構(gòu)。23. 【推薦】慎用 Object 的 clone 方法來拷貝對(duì)象。說明:對(duì)象 clone 方法默認(rèn)是淺拷貝,若想實(shí)現(xiàn)深拷貝需覆寫 clone 方法實(shí)現(xiàn)域?qū)ο蟮纳疃缺闅v式拷貝。

41、24. 【推薦】類成員與方法從嚴(yán):1)2)3)4)5)6)7)8)如果不外部直接通過 new 來創(chuàng)建對(duì)象,那么構(gòu)造方法必須是 private。工具類不有 public 或 default 構(gòu)造方法。類非 static 成員變量并且與子類共享,必須是 protected。類非 static 成員變量并且僅在本類使用,必須是private。類 static 成員變量如果僅在本類使用,必須是 private。若是 static 成員變量,考慮是否為 final。類成員方法只供類內(nèi)部調(diào)用,必須是 private。類成員方法只對(duì)繼承類公開,那么限制為 protected。說明:任何類、方法、參數(shù)、變量,

42、嚴(yán)控范圍。過于寬泛的范圍,不利于模塊解耦。思考:如果10/44Java 開發(fā)手冊(cè)是一個(gè) private 的方法,想刪除就刪除,一個(gè) public 的 service 成員方法或成員變量,刪除一下,不得手心會(huì)擔(dān)心的。汗嗎?變量像的小孩,盡量在的視線內(nèi),變量作用域太大,的到處跑,那么你(五)1.集合處理【強(qiáng)制】關(guān)于 hashCode 和 equals 的處理,遵循如下規(guī)則:1) 只要覆寫 equals,就必須覆寫 hashCode。2) 因?yàn)?Set的是不重復(fù)的對(duì)象,依據(jù) hashCode 和 equals 進(jìn)行寫這兩個(gè)方法。,所以 Set的對(duì)象必須覆3) 如果自定義對(duì)象作為 Map 的鍵,那么必

43、須覆寫hashCode 和 equals。說明:String 已覆寫 hashCode 和 equals 方法,所以我們可以愉快地使用 String 對(duì)象作為 key 來使用。2.【強(qiáng)制】ArrayList 的 subList 結(jié)果不可強(qiáng)轉(zhuǎn)成 ArrayList,否則會(huì)拋出 ClassCastException 異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。說明:subList 返回的是 ArrayList 的內(nèi)部類 SubList,并不是 ArrayList 而是ArrayList 的一個(gè)視圖

44、,對(duì)于 SubList 子列表的所有操作最終會(huì)反映到原列表上。3.【強(qiáng)制】使用 Map 的方法 keySet()/values()/entrySet()返回集合對(duì)象時(shí),不可以對(duì)其進(jìn)行添加元素操作,否則會(huì)拋出 UnsupportedOperationException 異常。【強(qiáng)制】Collections 類返回的對(duì)象,如:emptyList()/singletonList()等都是 immutable list,不可對(duì)其進(jìn)行添加或者刪除元素的操作。反例:如果無結(jié)果,返回 Collections.emptyList()空集合對(duì)象,調(diào)用方一旦進(jìn)行了添加元素的操作,就會(huì)觸發(fā) UnsupportedO

45、perationException 異常。4.5.【強(qiáng)制】在 subList 場(chǎng)景中,高度注意對(duì)原集合元素的增加或刪除,均會(huì)導(dǎo)致子列表的遍歷、增加、刪除產(chǎn)生 ConcurrentModificationException 異常?!緩?qiáng)制】使用集合轉(zhuǎn)數(shù)組的方法,必須使用集合的 toArray(T array),傳入的是類型完全一致、長度為 0 的空數(shù)組。6.反例:直接使用 toArray 無參方法現(xiàn) ClassCastException 錯(cuò)誤。正例:問題,此方法返回值只能是 Object類,若強(qiáng)轉(zhuǎn)其它類型數(shù)組將出List<String> list = new ArrayList<

46、>(2); list.add("guan");list.add("bao");String array = list.toArray(new String0);說明:使用 toArray 帶參方法,數(shù)組空間大小的 length: 1) 等于 0,動(dòng)態(tài)創(chuàng)建與 size 相同的數(shù)組,性能最好。2) 大于 0 但小于size,重新創(chuàng)建大小等于 size 的數(shù)組,增加 GC 負(fù)擔(dān)。11/44Java 開發(fā)手冊(cè)3) 等于 size,在高并,數(shù)組創(chuàng)建完成之后,size 正在變大的情,影響與上相同。4) 大于 size,空間浪費(fèi),且在 size 處null 值,

47、NPE 隱患。7.【強(qiáng)制】在使用 Collection 接口任何實(shí)現(xiàn)類的 addAll()方法時(shí),都要對(duì)輸入的集合參數(shù)進(jìn)行NPE。說明:在 ArrayList#addAll 方法的第一行代碼即 Object a = c.toArray(); 其中 c 為輸入集合參數(shù),如果為 null,則直接拋出異常。8.【強(qiáng)制】使用工具類 Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時(shí),不能使用其修改集合相關(guān)的方法,它的 add/remove/clear 方拋出 UnsupportedOperationException 異常。說明:asList 的返回對(duì)象是一個(gè) Arrays 內(nèi)部類,并沒有實(shí)現(xiàn)集合的修改

48、方法。Arrays.asList 體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,的數(shù)據(jù)仍是數(shù)組。String str = new String "yang", "hao" ;List list = Arrays.asList(str);第一種情況:list.add("yangguanbao"); 運(yùn)行時(shí)異常。第二種情況:str0 = "changed" 也會(huì)隨之修改,反之亦然。9.【強(qiáng)制】泛型通配符<? extends T>來接收返回的數(shù)據(jù),此寫法的泛型集合不能使用 add 方法,而<? super T>

49、;不能使用 get 方法,作為接口調(diào)用賦值時(shí)易出錯(cuò)。說明:擴(kuò)展說一下 PECS(Producer Extends Consumer Super)原則:第一、頻繁往外內(nèi)容的,適合用<? extends T>。第二、經(jīng)常往里的,適合用<? super T>10. 【強(qiáng)制】在無泛型限制定義的集合賦值給泛型限制的集合時(shí),在使用集合元素要進(jìn)行instanceof,避免拋出 ClassCastException 異常。說明:畢竟泛型是在 JDK5 后才出現(xiàn),考慮到向前兼容,編譯器是反例:非泛型集合與泛型集合互相賦值。List<String> generics = nul

50、l;List notGenerics = new ArrayList(10); notGenerics.add(new Object(); notGenerics.add(new Integer(1);generics = notGenerics;/ 此處拋出 ClassCastException 異常String string = generics.get(0);11. 【強(qiáng)制】不要在 foreach 循環(huán)里進(jìn)行元素的 remove/add 操作。remove 元素請(qǐng)使用Iterator 方式,如果并發(fā)操作,需要對(duì) Iterator 對(duì)象加鎖。正例:List<String> li

51、st = new ArrayList<>(); list.add("1");list.add("2");Iterator<String> iterator = list.iterator(); while (iterator.hasNext() String item = iterator.next(); if (刪除元素的條件) 12/44Java 開發(fā)手冊(cè)iterator.remove();反例:for (String item : list) if ("1".equals(item) list.remov

52、e(item);說明:以上代碼的執(zhí)行結(jié)果肯定會(huì)出乎大家的意料,那么試一下把“1”換成“2”,會(huì)是同樣的結(jié)果嗎?12. 【強(qiáng)制】在 JDK7 版本及以上,Comparator 實(shí)現(xiàn)類要滿足如下三個(gè)條件,不然 Arrays.sort,Collections.sort 會(huì)拋 IllegalArgumentException 異常。說明:三個(gè)條件如下1)2)3)x,y 的比較結(jié)果和 y,x 的比較結(jié)果相反。x>y,y>z,則 x>z。x=y,則 x,z 比較結(jié)果和 y,z 比較結(jié)果相同。反例:下例中沒有處理相等的情況,交換兩個(gè)對(duì)象可能會(huì)出現(xiàn)異常。new Comparator<S

53、tudent>() Overridepublic int compare(Student o1, Student o2) return o1.getId() > o2.getId() ? 1 : -1;結(jié)果并不互反,不符合第一個(gè)條件,在實(shí)際使用中13. 【推薦】集合泛型,在 JDK7 及以上,使用 diamond 語法或全省略。說明:菱形泛型,即 diamond,直接使用<>來指代前邊已經(jīng)指定的類型。正例:/ diamond 方式,即<>HashMap<String, String> userCache = new HashMap<>

54、(16);/ 全省略方式ArrayList<User> users = new ArrayList(10);14. 【推薦】集合初始化時(shí),指定集合初始值大小。說明:HashMap 使用 HashMap(int initialCapacity) 初始化。正例:initialCapacity = (需要的元素個(gè)數(shù) / 負(fù)載因子) + 1。注意負(fù)載因子(即 loader factor)默認(rèn)為 0.75,如果暫時(shí)無法確定初始值大小,請(qǐng)?jiān)O(shè)置為 16(即默認(rèn)值)。反例:HashMap 需要放置 1024 個(gè)元素,由于沒有設(shè)置容量初始大小,隨著元素不斷增加,容量 7 次被迫擴(kuò)大,resize 需

55、要重建 hash 表,嚴(yán)重影響性能。15. 【推薦】使用 entrySet 遍歷 Map 類集合 KV,而不是 keySet 方式進(jìn)行遍歷。說明:keySet 其實(shí)是遍歷了 2 次,一次是轉(zhuǎn)為 Iterator 對(duì)象,另一次是從 hashMap 中取出 key 所對(duì)應(yīng)的 value。而 entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8, 使用 Map.forEach 方法。13/44Java 開發(fā)手冊(cè)正例:values()返回的是 V 值集合,是一個(gè) list 集合對(duì)象;keySet()返回的是K 值集合,是一個(gè) Set 集合對(duì)象;entrySet()返回的是 K-V 值組

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論