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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

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

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

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

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

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

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

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

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

9、baba.ai.util、類名為 MessageUtils(此規(guī)則參考 spring 的框架結構)10. 【強制】避免在子父類的成員變量之間、或者不同代碼塊的局部變量之間采用完全相同名,使可讀性降低。說明:子類、父類成員變量名相同,即使是 public 類型的變量也是能夠通過編譯,而局部變量在同一方法內(nèi)的不同代碼塊中同名也是合法的,但是要避免使用。對于非 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. 【強制】杜絕完全不規(guī)范的縮寫,避免不知義。反例:AbstractClass“縮寫”命名成 AbsClass;condition“縮寫”命名成降低了代碼的可閱讀性。c

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

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

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

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

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

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

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

18、單獨的 constant 目錄下。:直接在類內(nèi)部 private static final 定義。5.【推薦】如果變量值僅在一個固定范圍內(nèi)變化用 enum 類型來定義。說明:如果名稱之外的延伸屬性應使用 enum 類型,下面正例中的數(shù)字就是延伸信息,表示一年中的第幾個季節(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、手冊(三)1.代碼格式【強制】如果是大括號內(nèi)為空,則簡潔地寫成即可,大括號中間無需換行和空格;如果是非空代碼塊則:1)2)3)4)左大括號前不換行。左大括號后換行。右大括號前換行。右大括號后還有 else 等代碼則不換行;表示終止的右大括號后必須換行。2.【強制】左小括號和字符之間不出現(xiàn)空格;同樣,右小括號和字符之間也不出現(xiàn)空格;而左大括號前需要空格。詳見第 5 條下方正例提示。反例:if (空格 a = b 空格)3.4.【強制】if/for/while/switch/do 等保留字與括號之間都必須加空格?!緩娭啤咳魏味?、三目運算符的左右兩邊都需要加一個空格。說明:運算符包括賦值運算符=、

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

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

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

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

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

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

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

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

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

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

30、float b = 0.9f - 0.8f;if (a = b) / 預期進入此代碼快,執(zhí)行其它業(yè)務邏輯/ 但事實上 a=b 的結果為falseFloat x = Float.valueOf(a); Float y = Float.valueOf(b); if (x.equals(y) / 預期進入此代碼快,執(zhí)行其它業(yè)務邏輯/ 但事實上 equals 的結果為false正例:(1) 指定一個誤差范圍,兩個浮點數(shù)的差值在此范圍之內(nèi),則認為是相等的。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 來定義值,再進行浮點數(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

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

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

34、l recommend2 = BigDecimal.valueOf(0.1);11. 關于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標準如下:1)2)3)【強制】所有的 POJO 類屬性必須使用包裝數(shù)據(jù)類型?!緩娭啤縍PC 方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型?!就扑]】所有的局部變量使用基本數(shù)據(jù)類型。說明:POJO 類屬性沒有初值是提醒使用者在需要使用時,必須者入庫檢查,使用者來保證。顯式地進行賦值,任何 NPE 問題,或正例:數(shù)據(jù)庫的結果可能是 null,因為自動拆箱,用基本數(shù)據(jù)類型接收有 NPE 風險。反例:比如顯示成交總額漲跌情況,即正負 x%,x 為基本數(shù)據(jù)類型,調(diào)用的 RPC 服務,調(diào)用不時

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

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

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

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

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

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

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

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

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

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

45、perationException 異常。4.5.【強制】在 subList 場景中,高度注意對原集合元素的增加或刪除,均會導致子列表的遍歷、增加、刪除產(chǎn)生 ConcurrentModificationException 異常?!緩娭啤渴褂眉限D(zhuǎn)數(shù)組的方法,必須使用集合的 toArray(T array),傳入的是類型完全一致、長度為 0 的空數(shù)組。6.反例:直接使用 toArray 無參方法現(xiàn) ClassCastException 錯誤。正例:問題,此方法返回值只能是 Object類,若強轉(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,動態(tài)創(chuàng)建與 size 相同的數(shù)組,性能最好。2) 大于 0 但小于size,重新創(chuàng)建大小等于 size 的數(shù)組,增加 GC 負擔。11/44Java 開發(fā)手冊3) 等于 size,在高并,數(shù)組創(chuàng)建完成之后,size 正在變大的情,影響與上相同。4) 大于 size,空間浪費,且在 size 處null 值,

47、NPE 隱患。7.【強制】在使用 Collection 接口任何實現(xiàn)類的 addAll()方法時,都要對輸入的集合參數(shù)進行NPE。說明:在 ArrayList#addAll 方法的第一行代碼即 Object a = c.toArray(); 其中 c 為輸入集合參數(shù),如果為 null,則直接拋出異常。8.【強制】使用工具類 Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時,不能使用其修改集合相關的方法,它的 add/remove/clear 方拋出 UnsupportedOperationException 異常。說明:asList 的返回對象是一個 Arrays 內(nèi)部類,并沒有實現(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"); 運行時異常。第二種情況:str0 = "changed" 也會隨之修改,反之亦然。9.【強制】泛型通配符<? extends T>來接收返回的數(shù)據(jù),此寫法的泛型集合不能使用 add 方法,而<? super T>

49、;不能使用 get 方法,作為接口調(diào)用賦值時易出錯。說明:擴展說一下 PECS(Producer Extends Consumer Super)原則:第一、頻繁往外內(nèi)容的,適合用<? extends T>。第二、經(jīng)常往里的,適合用<? super T>10. 【強制】在無泛型限制定義的集合賦值給泛型限制的集合時,在使用集合元素要進行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. 【強制】不要在 foreach 循環(huán)里進行元素的 remove/add 操作。remove 元素請使用Iterator 方式,如果并發(fā)操作,需要對 Iterator 對象加鎖。正例: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ā)手冊iterator.remove();反例:for (String item : list) if ("1".equals(item) list.remov

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

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

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

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

溫馨提示

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

評論

0/150

提交評論