版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
JAVA開發(fā)標(biāo)準(zhǔn)目錄TOC\o"1-3"\h\u301101范圍 3119082規(guī)范性引用文件 31758GB/T15496-2017企業(yè)標(biāo)準(zhǔn)體系-要求 3227513定義和術(shù)語 3258904要求 4161824.1編程規(guī)約 4254224.2.異常日志 3349244.3數(shù)據(jù)庫 37218234.4工程結(jié)構(gòu) 43262424.5設(shè)計(jì)規(guī)約 4817284.6附則 50JAVA開發(fā)標(biāo)準(zhǔn)范圍本標(biāo)準(zhǔn)規(guī)定了公司信息系統(tǒng)JAVA開發(fā)要求。規(guī)范性引用文件下列文件中的條款通過本標(biāo)準(zhǔn)的引用而成為本標(biāo)準(zhǔn)的條款。凡是注日期的引用文件,其隨后所有的修改單(不包括勘誤的內(nèi)容)或修訂版均不適用于本標(biāo)準(zhǔn),然而,鼓勵(lì)根據(jù)本標(biāo)準(zhǔn)達(dá)成協(xié)議的各方研究是否可使用這些文件的最新版本。凡是不注日期的引用文件,其最新版本適用于本標(biāo)準(zhǔn)。GB/T15496-2017企業(yè)標(biāo)準(zhǔn)體系-要求GB/T15497-2017企業(yè)標(biāo)準(zhǔn)體系技術(shù)標(biāo)準(zhǔn)體系GB/T15498-2017企業(yè)標(biāo)準(zhǔn)體系-基礎(chǔ)保障GB/T19273-2017企業(yè)標(biāo)準(zhǔn)體系-評(píng)價(jià)與改進(jìn)ISO9001質(zhì)量管理體系標(biāo)準(zhǔn)ISO27001信息安全管理體系標(biāo)準(zhǔn)定義和術(shù)語下列術(shù)語和定義適用于本標(biāo)準(zhǔn)。要求編程規(guī)約命名風(fēng)格 【強(qiáng)制】代碼中的命名均不能以下劃線或美元符號(hào)開始,也不能以下劃線或美元符號(hào)結(jié)束。反例:_name/ name/$name/name_/name$/name__ 【強(qiáng)制】代碼中的命名嚴(yán)禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。說明:正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。注意,即使純拼音命名方式也要避免采用。alibaba/taobao/youku/hangzhou等國際通用的名稱,可視同英文。DaZhePromotion[打折]/getPingfenByName()[評(píng)分]/int某變量= 【強(qiáng)制】類名使用UpperCamelCase風(fēng)格,但以下情形例外:DO/BO/DTO/VO/AO/PO/UID等。正例:MarcoPolo UserDO XmlService TcpUdpDeal/TaPromotion反例:macroPolo UserDo XMLService TCPUDPDeal/TAPromotion【強(qiáng)制】方法名、參數(shù)名、成員變量、局部變量都統(tǒng)一使用lowerCamelCase風(fēng)格,必須遵從駝峰形式。正例:localValue/getHttpMessage()/inputUserId 【強(qiáng)制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達(dá)完整清楚,不要嫌名字長(zhǎng)。MAX_STOCK_COUNTMAX_COUNT 【強(qiáng)制】抽象類命名使用Abstract或Base開頭;異常類命名使用Exception結(jié)尾;測(cè)試類命名以它要測(cè)試的類的名稱Test結(jié)尾。 【強(qiáng)制】類型與中括號(hào)緊挨相連來表示數(shù)組。正例:定義整形數(shù)組int[]arrayDemo;反例:在main參數(shù)中,使用Stringargs[]來定義。 【強(qiáng)制】POJO類中布爾類型的變量,都不要加is前綴,否則部分框架解析會(huì)引起序列化錯(cuò)誤。反例:定義為基本數(shù)據(jù)類型BooleanisDeleted的屬性,它的方法也是isDeleted(),RPC是deleted,導(dǎo)致屬性獲取不到,進(jìn)而拋出異常。 【強(qiáng)制】包名統(tǒng)一使用小寫,點(diǎn)分隔符之間有且僅有一個(gè)自然語義的英語單詞。包名統(tǒng)一使用單數(shù)形式,但是類名如果有復(fù)數(shù)含義,類名可以使用復(fù)數(shù)形式。com.alibaba.ai.util為MessageUtils(此規(guī)則參考spring的框架結(jié)構(gòu))【強(qiáng)制】杜絕完全不規(guī)范的縮寫,避免望文不知義。反例:AbstractClass“縮寫”命名成 AbsClass;condition“縮寫命名成condi,此類隨意縮寫嚴(yán)重降低了代碼的可閱讀性?!就扑]】為了達(dá)到代碼自解釋的目標(biāo),任何自定義編程元素在命名時(shí),使用盡量完整的單詞組合來表達(dá)其意。正例:在 JDK中,表達(dá)原子更新的類名為:AtomicReferenceFieldUpdater。反例:變量inta的隨意命名方式?!就扑]】如果模塊、接口、類、方法使用了設(shè)計(jì)模式,在命名時(shí)需體現(xiàn)出具體模式。說明:將設(shè)計(jì)模式體現(xiàn)在名字中,有利于閱讀者快速理解架構(gòu)設(shè)計(jì)理念。publicclassOrderFactory;publicclassLoginProxy;publicclassResourceObserver;【推薦】接口類中的方法和屬性不要加任何修飾符號(hào)(public也不要加),保持代碼的簡(jiǎn)潔性,并加上有效的Javadoc注釋。盡量不要在接口里定義變量,如果一定要定義變量,肯定是與接口方法相關(guān),并且是整個(gè)應(yīng)用的基礎(chǔ)常量。正例:接口方法簽名voidcommit();接口基礎(chǔ)常量StringCOMPANY="alibaba";反例:接口方法定義publicabstractvoidf();JDK8中接口允許有默認(rèn)實(shí)現(xiàn),那么這個(gè)default方法,是對(duì)所有實(shí)現(xiàn)類都有價(jià)值的默認(rèn)實(shí)現(xiàn)。接口和實(shí)現(xiàn)類的命名有兩套規(guī)則:【強(qiáng)制】對(duì)于Service和DAO類,基于SOA的理念,暴露出來的服務(wù)一定是接口,內(nèi)部的實(shí)現(xiàn)類用Impl的后綴與接口區(qū)別。CacheServiceImpl實(shí)現(xiàn)CacheService接口?!就扑]】如果是形容能力的接口名稱,取對(duì)應(yīng)的形容詞為接口名(able的形式)AbstractTranslator實(shí)現(xiàn)Translatable接口。常量定義 【強(qiáng)制】不允許任何魔法值(即未經(jīng)預(yù)先定義的常量)直接出現(xiàn)在代碼中。反例:Stringkey="Id#taobao_"+tradeId;cache.put(key,value); 【強(qiáng)制】在long或者Long賦值時(shí),數(shù)值后使用大寫的L,不能是小寫的l,小寫容易跟數(shù)字1混淆,造成誤解。Longa2l;寫的是數(shù)字的21Long型的 【推薦】不要使用一個(gè)常量類維護(hù)所有常量,要按常量功能進(jìn)行歸類,分開維護(hù)。說明:大而全的常量類,雜亂無章,使用查找功能才能定位到修改的常量,不利于理解和維護(hù)。正例:緩存相關(guān)常量放在類CacheConsts下;系統(tǒng)配置相關(guān)常量放在類ConfigConsts下?!就扑]】常量的復(fù)用層次有五層:跨應(yīng)用共享常量、應(yīng)用內(nèi)共享常量、子工程內(nèi)共享常量、包內(nèi)共享常量、類內(nèi)共享常量。1) 跨應(yīng)用共享常量:放置在二方庫中,通常是client.jar中的constant目錄下。應(yīng)用內(nèi)共享常量:放置在一方庫中,通常是子模塊中的constant目錄下。反例:易懂變量也要統(tǒng)一定義成應(yīng)用內(nèi)共享常量,兩位攻城師在兩個(gè)類中分別定義了表示“是”的變量:類ApublicstaticfinalStringYES="yes";類BpublicstaticfinalStringYES="y";A.YES.equals(B.YES),預(yù)期是true,但實(shí)際返回為false,導(dǎo)致線上問題。子工程內(nèi)部共享常量:即在當(dāng)前子工程的constant目錄下。包內(nèi)共享常量:即在當(dāng)前包下單獨(dú)的constant目錄下。5)類內(nèi)共享常量:直接在類內(nèi)部privatestaticfinal定義。 【推薦】如果變量值僅在一個(gè)固定范圍內(nèi)變化用enum類型來定義。說明:如果存在名稱之外的延伸屬性應(yīng)使用enum類型,下面正例中的數(shù)字就是延伸信息,表示一年中的第幾個(gè)季節(jié)。正例:publicenumSeasonEnumSPRING(1),SUMMER(2),AUTUMN(3),WINTER(4);privateintseq;SeasonEnum(intseq){this.seq=seq;代碼格式 【強(qiáng)制】大括號(hào)的使用約定。如果是大括號(hào)內(nèi)為空,則簡(jiǎn)潔地寫成{}即可,不需要換行;如果是非空代碼塊則:左大括號(hào)前不換行。左大括號(hào)后換行。右大括號(hào)前換行。右大括號(hào)后還有else等代碼則不換行;表示終止的右大括號(hào)后必須換行。 【強(qiáng)制】左小括號(hào)和字符之間不出現(xiàn)空格;同樣,右小括號(hào)和字符之間也不出現(xiàn)空格;而左大括號(hào)前需要空格。詳見第5條下方正例提示。if(空格a==b空格) 【強(qiáng)制】if/for/while/switch/do等保留字與括號(hào)之間都必須加空格。 【強(qiáng)制】任何二目、三目運(yùn)算符的左右兩邊都需要加一個(gè)空格。說明:運(yùn)算符包括賦值運(yùn)算符=、邏輯運(yùn)算符&&、加減乘除符號(hào)等?!緩?qiáng)制】采用4個(gè)空格縮進(jìn),禁止使用tab字符。說明:如果使用tab縮進(jìn),必須設(shè)置1個(gè)tab為4個(gè)空格。IDEA設(shè)置 tab為 4個(gè)空格時(shí),請(qǐng)勿勾選 Usetabcharacter而在eclipse中必須勾選insertspacesfortabs。正例:(1-5點(diǎn)publicstaticvoidmain(String[]args)/縮進(jìn)4個(gè)空格Stringsay="hello";/運(yùn)算符的左右必須有一個(gè)空格intflag=/關(guān)鍵詞if與括號(hào)之間必須有一個(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é)束,則必須換行【強(qiáng)制】注釋的雙斜線與注釋內(nèi)容之間有且僅有一個(gè)空格。正例:/這是示例注釋,請(qǐng)注意在雙斜線之后有一個(gè)空格Stringygb=newString(); 【強(qiáng)制】單行字符數(shù)限制不超過120個(gè),超出需要換行,換行時(shí)遵循如下原則:第二行相對(duì)第一行縮進(jìn)4個(gè)空格,從第三行開始,不再繼續(xù)縮進(jìn),參考示例。運(yùn)算符與下文一起換行。方法調(diào)用的點(diǎn)符號(hào)與下文一起換行。方法調(diào)用中的多個(gè)參數(shù)需要換行時(shí),在逗號(hào)后進(jìn)行。在括號(hào)前不要換行,見反例。正例:StringBuffersb=newStringBuffer();/超過120個(gè)字符的情況下,換行縮進(jìn)4個(gè)空格,點(diǎn)號(hào)和方法名稱一起換行sb.append("zi").append("xin")append("huang")append("huang")append("huang");反例:StringBuffersb=newStringBuffer(); 超過 120個(gè)字符的情況下,不要在括號(hào)前換行sb.append("zi").append("xin")...append("huang");/參數(shù)很多的方法調(diào)用可能超過120個(gè)字符,不要在逗號(hào)前換行method(args1,args2,args3,...,argsX); 【強(qiáng)制】方法參數(shù)在定義和傳入時(shí),多個(gè)參數(shù)逗號(hào)后邊必須加空格。正例:下例中實(shí)參的args1,后邊必須要有一個(gè)空格。method(args1,args2,args3); 【強(qiáng)制】IDE的textfileencoding設(shè)置為UTF-8;IDE中文件的換行符使用Unix格式,不要使用Windows格式?!就扑]】單個(gè)方法的總行數(shù)不超過80行。說明:包括方法簽名、結(jié)束右大括號(hào)、方法內(nèi)代碼、注釋、空行、回車及任何不可見字符的總行數(shù)不超過80行。正例:代碼邏輯分清紅花和綠葉,個(gè)性和共性,綠葉邏輯單獨(dú)出來成為額外方法,使主干代碼更加清晰;共性邏輯抽取成為共性方法,便于復(fù)用和維護(hù)?!就扑]】沒有必要增加若干空格來使某一行的字符與上一行對(duì)應(yīng)位置的字符對(duì)齊。正例:intone=1;longtwo=2L;floatthree=3F;StringBuffersb=newStringBuffer();說明:增加sb這個(gè)變量,如果需要對(duì)齊,則給a、b、c都要增加幾個(gè)空格,在變量比較多的情況下,是非常累贅的事情?!就扑]】不同邏輯、不同語義、不同業(yè)務(wù)的代碼之間插入一個(gè)空行分隔開來以提升可讀性。說明:任何情形,沒有必要插入多個(gè)空行進(jìn)行隔開。OOP 【強(qiáng)制】避免通過一個(gè)類的對(duì)象引用訪問此類的靜態(tài)變量或靜態(tài)方法,無謂增加編譯器解析成本,直接用類名來訪問即可?!緩?qiáng)制】所有的覆寫方法,必須加@Override注解。說明:getObject()與get0bject()的問題。一個(gè)是字母的O,一個(gè)是數(shù)字的0,加@Override可以準(zhǔn)確判斷是否覆蓋成功。另外,如果在抽象類中對(duì)方法簽名進(jìn)行修改,其實(shí)現(xiàn)類會(huì)馬上編譯報(bào)錯(cuò)。 【強(qiáng)制】相同參數(shù)類型,相同業(yè)務(wù)含義,才可以使用Java的可變參數(shù),避免使用Object。說明:可變參數(shù)必須放置在參數(shù)列表的最后。(提倡同學(xué)們盡量不用可變參數(shù)編程)正例:publicList<User>listUsers(Stringtype,Long...ids){...} 【強(qiáng)制】外部正在調(diào)用或者二方庫依賴的接口,不允許修改方@Deprecated注解,并清晰地說明采用的新接口或者新服務(wù)是什么。【強(qiáng)制】不能使用過時(shí)的類或方法。.URLDecoder中的方法decode(StringencodeStr)這個(gè)方法已經(jīng)過時(shí),應(yīng)該使用雙參數(shù)decode(Stringsource,Stringencode)。接口提供方既然明確是過時(shí)接口,那么有義務(wù)同時(shí)提供新的接口;作為調(diào)用方來說,有義務(wù)去考證過時(shí)方法的新實(shí)現(xiàn)是什么。 【強(qiáng)制】Object的equals方法容易拋空指針異常,應(yīng)使用常量或確定有值的對(duì)象來調(diào)用equals。正例:"test".equals(object);object.equals("test");說明:推薦使用java.util.Objects#equals(JDK7引入的工具類) 【強(qiáng)制】所有的相同類型的包裝類對(duì)象之間值的比較,全部使用equalsIntegervar=?在-128至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)生,并不會(huì)復(fù)用已有對(duì)象,這是一個(gè)大坑,推薦使用equals方法進(jìn)行判斷。關(guān)于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標(biāo)準(zhǔn)如下:【強(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ù)xx為基本數(shù)據(jù)類型,調(diào)用的RPC服務(wù),調(diào)用不成功時(shí),返回的是默認(rèn)值,頁面顯示為0%,這是不合理的,應(yīng)該顯示成中劃線。所以包裝數(shù)據(jù)類型的null值,能夠表示額外的信息,如:遠(yuǎn)程調(diào)用失敗,異常退出。 【強(qiáng)制】定義DO/DTO/VO等POJO類時(shí),不要設(shè)定任何屬性默認(rèn)值。反例:POJO類的gmtCreate默認(rèn)值為newDate(),但是這個(gè)屬性在數(shù)據(jù)提取時(shí)并沒有置入具體值,在更新其它字段時(shí)又附帶更新了此字段,導(dǎo)致創(chuàng)建時(shí)間被修改成當(dāng)前時(shí)間。【強(qiáng)制】序列化類新增屬性時(shí),請(qǐng)不要修 serialVersionUID字段,避免反序列失??;如果完全不兼容升級(jí)避免反序列化混亂那么請(qǐng)修改serialVersionUID值。說明:注意serialVersionUID不一致會(huì)拋出序列化運(yùn)行時(shí)異常?!緩?qiáng)制】構(gòu)造方法里面禁止加入任何業(yè)務(wù)邏輯,如果有初始化邏輯,請(qǐng)放在init方法中?!緩?qiáng)制】POJO類必須寫toString方法。使用IDE中的source>generatetoString時(shí),如果繼承了另一個(gè)POJO類,注意在前面加一下super.toString。POJO的toString()方法打印其屬性值,便于排查問題。POJOxxx的isXxxgetXxx()方法。說明:框架在調(diào)用屬性xxx的提取方法時(shí),并不能確定哪個(gè)方法一定是被優(yōu)先調(diào)用到?!就扑]】使用索引訪問用String的split方法得到的數(shù)拋IndexOutOfBoundsException的風(fēng)險(xiǎn)。說明:Stringstr="a,b,c,,";String[]ary=str.split(","); System.out.println(ary.length);【推薦】當(dāng)一個(gè)類有多個(gè)構(gòu)造方法,或者多個(gè)同名方法,這些方法應(yīng)該按順序放置在一起,便于閱讀,此條規(guī)則優(yōu)先于第 條規(guī)則?!就扑]】類內(nèi)方法定義的順序依次是:公有方法或保護(hù)方法>私有方法>getter/setter方法。說明:公有方法是類的調(diào)用者和維護(hù)者最關(guān)心的方法,首屏展示最好;保護(hù)方法雖然只是子類關(guān)心,也可能是“模板設(shè)計(jì)模式”下的核心方法;而私有方法外部一般不需要特別關(guān)心,是一個(gè)黑盒Service和DAO的getter/setter方法放在類體最后?!就扑]】setter方法中,參數(shù)名稱與類成員變量名稱一致,this.成員名=參數(shù)名。在getter/setter方法中,不要增加業(yè)務(wù)邏輯,增加排查問題的難度。反例:publicIntegergetData(){if(condition){returnthis.data+100;}elsereturnthis.data-100;【推薦】循環(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)存資源浪費(fèi)。反例:Stringstr="start";for(inti=0;i<100;i++){str=str+"hello";【推薦】final可以聲明類、成員變量、方法、以及本地變量,下列情況使用final關(guān)鍵字:不允許被繼承的類,如:String類。不允許修改引用的域?qū)ο?。不允許被重寫的方法,如:POJO類的setter方法。不允許運(yùn)行過程中重新賦值的局部變量。避免上下文重復(fù)使用一個(gè)變量,使用final描述可以強(qiáng)制重新定義一個(gè)變量,方便更好地進(jìn)行重構(gòu)?!就扑]】慎用Object的clone方法來拷貝對(duì)象。說明:對(duì)象的clone方法默認(rèn)是淺拷貝,若想實(shí)現(xiàn)深拷貝需要重寫clone方法實(shí)現(xiàn)域?qū)ο蟮纳疃缺闅v式拷貝?!就扑]】類成員與方法訪問控制從嚴(yán):如果不允許外部直接通過new來創(chuàng)建對(duì)象,那么構(gòu)造方法必須是private。工具類不允許有public或default構(gòu)造方法。3) 類非 static 成員變量并且與子類共享,必須是protected。4) 類非 static 成員變量并且僅在本類使用,必須是private。 static 成員變量如果僅在本類使用,必須是private。若是static成員變量,考慮是否為final類成員方法只供類內(nèi)部調(diào)用,必須是private類成員方法只對(duì)繼承類公開,那么限制為protected。說明:任何類、方法、參數(shù)、變量,嚴(yán)控訪問范圍。過于寬泛的訪問范圍,不利于模塊解耦。思考:如果是一個(gè)private的方法,想刪除就刪除,可是一個(gè)public的service成員方法或成員變量,刪除一下,不得手心冒點(diǎn)汗嗎?變量像自己的小孩,盡量在自己的視線內(nèi),變量作用域太大,無限制的到處跑,那么你會(huì)擔(dān)心的。集合處理 【強(qiáng)制】關(guān)于hashCode和equals的處理,遵循如下規(guī)則:1)只要重寫equals,就必須重寫hashCode)因?yàn)镾et存儲(chǔ)的是不重復(fù)的對(duì)象,依據(jù)hashCode和equals進(jìn)行判斷,所以Set存儲(chǔ)的對(duì)象必須重寫這兩個(gè)方法。)Map寫hashCode和equals。說明:String重寫了hashCode和equals方法,所以我們可以非常愉快地使用String對(duì)象作為key來使用。 【強(qiáng)制】ArrayList的subList結(jié)果不可強(qiáng)轉(zhuǎn)成ArrayListClassCastException即java.util.RandomAccessSubListcannotbecastjava.util.ArrayListsubList返回的是ArrayList的內(nèi)部類SubListArrayList而是ArrayList的一個(gè)視圖,對(duì)于SubList子列表的所有操作最終會(huì)反映到原列表上。 【強(qiáng)制】在subList場(chǎng)景中,高度注意對(duì)原集合元素的增加或刪除,均會(huì)導(dǎo)致子列表的遍歷、增加、刪除產(chǎn)生ConcurrentModificationException異常。 的toArray(T[]array),傳入的是類型完全一樣的數(shù)組,大小就是list.size()。說明:使用toArray帶參方法,入?yún)⒎峙涞臄?shù)組空間不夠大時(shí),toArray方法內(nèi)部將重新分配內(nèi)存空間,并返回新數(shù)組地址;如果數(shù)組元素個(gè)數(shù)大于實(shí)際所需,下標(biāo)為[list.size()]的數(shù)組元素將被置為null,其它數(shù)組元素保持原值,因此最好將方法入?yún)?shù)組大小定義與集合元素個(gè)數(shù)一致。正例:List<String>list=newArrayList<String>(2);list.add("guan");list.add("bao");String[]array=newString[list.size()];array=list.toArray(array);反例:直接使用toArray無參方法存在問題,此方法返回值只能是Object[]類,若強(qiáng)轉(zhuǎn)其它類型數(shù)組將出現(xiàn)ClassCastException錯(cuò)誤。 【強(qiáng)制使用工具類Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時(shí),不能使用其修改集合相關(guān)的方法,它的 add/remove/clear方法會(huì)拋出UnsupportedOperationException異常。說明:asList的返回對(duì)象是一個(gè)Arrays內(nèi)部類,并沒有實(shí)現(xiàn)集合的修改方法。Arrays.asList體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺(tái)的數(shù)據(jù)仍是數(shù)組。String[]str=newString[]{"you","wu"};Listlist=Arrays.asList(str);第一種情況:list.add("yangguanbao");運(yùn)行時(shí)異常。第二種情況:str[0]="gujin";那么list.get(0)也會(huì)隨之修改。 【強(qiáng)制】泛型通配符<?extendsT>來接收返回的數(shù)據(jù),此寫法的泛型集合不能使用add方法,而<?superT>不能使用get方法,作為接口調(diào)用賦值時(shí)易出錯(cuò)。說明:擴(kuò)展說一下PECS(ProducerExtendsConsumerSuper)原則:第一、頻繁往外讀取內(nèi)容的,適合用<?extendsT>。第二、經(jīng)常往里插入的,適合用<?superT>。 【強(qiáng)制】不要在foreach循環(huán)里進(jìn)行元素的remove/add操作。remove元素請(qǐng)使用Iterator方式,如果并發(fā)操作,需要對(duì)Iterator對(duì)象加鎖。正例:List<String>list=newArrayList<>();list.add("1");list.add("2");Iterator<String>iterator=list.iterator();while(iterator.hasNext()){Stringitem=iterator.next();if(刪除元素的條件){iterator.remove();反例:for(Stringitem:list){if("1".equals(item)){list.remove(item);說明:以上代碼的執(zhí)行結(jié)果肯定會(huì)出乎大家的意料,那么試一下把“12”,會(huì)是同樣的結(jié)果嗎? 【強(qiáng)制】在JDK7版本及以上,Comparator實(shí)現(xiàn)類要滿足Arrays.sortCollections.sort會(huì)報(bào)IllegalArgumentException異常。說明:三個(gè)條件如下1)xy的比較結(jié)果和yx的比較結(jié)果相反。2)x>yy>zx>z。3)x=yxz比較結(jié)果和yz比較結(jié)果相同。反例:下例中沒有處理相等的情況,實(shí)際使用中可能會(huì)出現(xiàn)異常:newComparator<Student>(){@Overridepublicintcompare(Studento1,Studento2){returno1.getId()>o2.getId()?1:-1; 【推薦】集合泛型定義時(shí),在JDK7及以上,使用diamond語法或全省略。說明:菱形泛型,即diamond,直接使用<>來指代前邊已經(jīng)指定的類型。正例://<>diamond方式HashMap<String,String>userCache=newHashMap<>(16);/全省略方式ArrayList<User>users=newArrayList(10);【推薦】集合初始化時(shí),指定集合初始值大小。說明:HashMap使用HashMap(intinitialCapacity)初始化。initialCapacity=(需要存儲(chǔ)的元素個(gè)數(shù)/負(fù)載因子)+1。注意負(fù)載因子(loaderfactor)默認(rèn)為0.75果暫時(shí)無法確定初始值大小,請(qǐng)?jiān)O(shè)置為16(即默認(rèn)值)反例:HashMap需要放置1024個(gè)元素,由于沒有設(shè)置容量初始大小,隨著元素不斷增加,容量7次被迫擴(kuò)大,resize需要重建entrySet遍歷Map類集合KV是keySet方式進(jìn)行遍歷。說明:keySet其實(shí)是遍歷了2次,一次是轉(zhuǎn)為IteratorhashMap中取出key所對(duì)應(yīng)的value而entrySetkey和value了entry中,效率更高。如果是JDK8,使用Map.foreach方法。values()返回的是V值集合,是一個(gè)list集合對(duì)象;keySet()返回的是K值集合,是一個(gè)Set集合對(duì)象;entrySet()返回的是K-V值組合集合。集合類KeyValueSuper說明Hashtable集合類KeyValueSuper說明Hashtable允許nulDictionary線程安全ConcurrentHashM允許nulAbstractMap(JDK8:CAS)TreeMap允許nulAbstractMap線程不安全HashMap AbstractMap線程不安全反例:由于HashMap的干擾,很多人認(rèn)ConcurrentHashMapnull儲(chǔ)null值時(shí)會(huì)拋出NPE異常。【參考】合理利用好集合的有序性(sort)和穩(wěn)定性(order),避免集合的無序性(unsort)和不穩(wěn)定性(unorder)帶來的負(fù)面影響。說明:有序性是指遍歷的結(jié)果是按某種比較規(guī)則依次排列的。ArrayList是order/unsortHashMap是unorder/unsortTreeSet是order/sort。【參考】利用Set元素唯一的特性,可以快速對(duì)一個(gè)集合進(jìn)行去重操作,避免使用List的contains方法進(jìn)行遍歷、對(duì)比、去重操作。控制語句 switchcase過break/return等來終止,要么注釋說明程序?qū)⒗^續(xù)執(zhí)行到哪一個(gè)case為止;在一個(gè)switch塊內(nèi),都必須包含一個(gè)default語句并且放在最后,即使空代碼。 【強(qiáng)制】在if/else/for/while/do語句中必須使用大括號(hào)。即使只有一行代碼,避免采用單行的編碼方式:if(condition)statements; 【強(qiáng)制】在高并發(fā)場(chǎng)景中,避免使用”等于”判斷作為中斷或退出的條件。說明:如果并發(fā)控制沒有處理好,容易產(chǎn)生等值判斷被“擊穿”的情況,使用大于或小于的區(qū)間判斷條件來代替。反例:判斷剩余獎(jiǎng)品數(shù)量等于0時(shí),終止發(fā)放獎(jiǎng)品,但因?yàn)椴l(fā)處理錯(cuò)誤導(dǎo)致獎(jiǎng)品數(shù)量瞬間變成了負(fù)數(shù),這樣的話,活動(dòng)無法終止。 【推薦】表達(dá)異常的分支時(shí),少用if-else方式,這種方式可以改寫成:if(condition)...returnobj;/接著寫else的業(yè)務(wù)邏輯代碼;說明:如果非得使用 if()...elseif()...else...方式表達(dá)邏輯,【強(qiáng)制】避免后續(xù)代碼維護(hù)困難,請(qǐng)勿超過3層。正例:超過3層的if-else的邏輯判斷代碼可以使用衛(wèi)語句、策略模式、狀態(tài)模式等來實(shí)現(xiàn),其中衛(wèi)語句示例如下:publicvoidtoday()if(isBusy())System.out.println(“changetime.”);return;if(isFree())System.out.println(“gototravel.”);return;System.out.println(“stayathometolearnAlibabaJavaCodingGuidelines.”);return; 【推薦】除常用方法(如getXxx/isXxx)等外,不要在條件判斷中執(zhí)行其它復(fù)雜的語句,將復(fù)雜邏輯判斷的結(jié)果賦值給一個(gè)有意義的布爾變量名,以提高可讀性。說明:很多if語句內(nèi)的邏輯相當(dāng)復(fù)雜,閱讀者需要分析條件表達(dá)式的最終結(jié)果,才能明確什么樣的條件執(zhí)行什么樣的語句,那么,如果閱讀者分析邏輯表達(dá)式錯(cuò)誤呢?正例:/偽代碼如下finalbooleanexisted=(file.open(fileName,"w")!=null)&&(...)||(...);if(existed){...反例:if((file.open(fileName,"w")!=null) (...)||(...)){... 【推薦】循環(huán)體中的語句要考量性能,以下操作盡量移至循環(huán)體外處理,如定義對(duì)象、變量、獲取數(shù)據(jù)庫連接,進(jìn)行不必要的try-catch操作(這個(gè)try-catch是否可以移至循環(huán)體外)【推薦】避免采用取反邏輯運(yùn)算符。說明:取反邏輯不利于快速理解,并且取反邏輯寫法必然存在對(duì)應(yīng)的正向邏輯寫法。正例:使用if(x<628)來表達(dá)x小于628反例:使用if(!(x>=628))來表達(dá)x小于628 【推薦】接口入?yún)⒈Wo(hù),這種場(chǎng)景常見的是用作批量操作的接口。 【參考】下列情形,需要進(jìn)行參數(shù)校驗(yàn):1)調(diào)用頻次低的方法。執(zhí)行時(shí)間開銷很大的方法。此情形中,參數(shù)校驗(yàn)時(shí)間幾乎可以忽略不計(jì),但如果因?yàn)閰?shù)錯(cuò)誤導(dǎo)致中間執(zhí)行回退,或者錯(cuò)誤,那得不償失。需要極高穩(wěn)定性和可用性的方法。對(duì)外提供的開放接口,不管是RPC/API/HTTP接口。敏感權(quán)限入口。【參考】下列情形,不需要進(jìn)行參數(shù)校驗(yàn):極有可能被循環(huán)調(diào)用的方法。但在方法說明里必須注明外部參數(shù)檢查要求。底層調(diào)用頻度比較高的方法。畢竟是像純凈水過濾的最后一道,參數(shù)錯(cuò)誤不太可能到底層才會(huì)暴露問題。一般DAO層與Service層都在同一個(gè)應(yīng)用中,部署在同一臺(tái)服務(wù)器中,所以DAO的參數(shù)校驗(yàn),可以省略。被聲明成private只會(huì)被自己代碼所調(diào)用的方法,如果能夠確定調(diào)用方法的代碼傳入?yún)?shù)已經(jīng)做過檢查或者肯定不會(huì)有問題,此時(shí)可以不校驗(yàn)參數(shù)。注釋規(guī)約 【強(qiáng)制】類、類屬性、類方法的注釋必須使用Javadoc規(guī)范,使用/***/格式,不得使用//xxx方式。說明:在IDE編輯窗口中,Javadoc方式會(huì)提示相關(guān)注釋,生成Javadoc可以正確輸出相應(yīng)注釋;在IDE中,工程調(diào)用方法時(shí),不進(jìn)入方法即可懸浮提示方法、參數(shù)、返回值的意義,提高閱讀效率。 ()用Javadoc注釋、除了返回值、參數(shù)、異常說明外,還必須指出該方法做什么事情,實(shí)現(xiàn)什么功能。說明:對(duì)子類的實(shí)現(xiàn)要求,或者調(diào)用注意事項(xiàng),請(qǐng)一并說明?!緩?qiáng)制】所有的類都必須添加創(chuàng)建者和創(chuàng)建日期。 【強(qiáng)制】方法內(nèi)部單行注釋,在被注釋語句上方另起一行,使用//注釋。方法內(nèi)部多行注釋使用/**/注釋,注意與代碼對(duì)齊。 【強(qiáng)制】所有的枚舉類型字段必須要有注釋,說明每個(gè)數(shù)據(jù)項(xiàng)的用途。 【推薦】與其“半吊子”英文來注釋,不如用中文注釋把問題說清楚。專有名詞與關(guān)鍵字保持英文原文即可。TCP連接超時(shí)”解釋成“傳輸控制協(xié)議連接超時(shí)”,理解反而費(fèi)腦筋。 【推薦】代碼修改的同時(shí),注釋也要進(jìn)行相應(yīng)的修改,尤其是參數(shù)、返回值、異常、核心邏輯等的修改。說明:代碼與注釋更新不同步,就像路網(wǎng)與導(dǎo)航軟件更新不同步一樣,如果導(dǎo)航軟件嚴(yán)重滯后,就失去了導(dǎo)航的意義。 【參考】謹(jǐn)慎注釋掉代碼。在上方詳細(xì)說明,而不是簡(jiǎn)單地注釋掉。如果無用,則刪除。說明:代碼被注釋掉有兩種可能性:1)后續(xù)會(huì)恢復(fù)此段代碼邏輯。2)永久不用。前者如果沒有備注信息,難以知曉注釋動(dòng)機(jī)。后者建議直接刪掉(代碼倉庫保存了歷史代碼) 【參考】對(duì)于注釋的要求:第一、能夠準(zhǔn)確反應(yīng)設(shè)計(jì)思想和代碼邏輯;第二、能夠描述業(yè)務(wù)含義,使別的程序員能夠迅速了解到代碼背后的信息。完全沒有注釋的大段代碼對(duì)于閱讀者形同天書,注釋是給自己看的,即使隔很長(zhǎng)時(shí)間,也能清晰理解當(dāng)時(shí)的思路;注釋也是給繼任者看的,使其能夠快速接替自己的工作?!緟⒖肌亢玫拿?、代碼結(jié)構(gòu)是自解釋的,注釋力求精簡(jiǎn)準(zhǔn)確、表達(dá)到位。避免出現(xiàn)注釋的一個(gè)極端:過多過濫的注釋,代碼的邏輯一旦修改,修改注釋是相當(dāng)大的負(fù)擔(dān)。反例:/putelephantintofridgeput(elephant,fridge);putelephant和fridge,已經(jīng)說明了這是在干什么,語義清晰的代碼不需要額外的注釋?!緟⒖肌刻厥庾⑨寴?biāo)記,請(qǐng)注明標(biāo)記人與標(biāo)記時(shí)間。注意及時(shí)處理這些標(biāo)記,通過標(biāo)記掃描,經(jīng)常清理此類標(biāo)記。線上故障有時(shí)候就是來源于這些標(biāo)記處的代碼。待辦事宜(TODO):(標(biāo)記人,標(biāo)記時(shí)間,[預(yù)計(jì)處理時(shí)間])個(gè)Javadoc的標(biāo)簽,目前的Javadoc還沒有實(shí)現(xiàn),但已經(jīng)被廣泛使用。只能應(yīng)用于類,接口和方法(因?yàn)樗且粋€(gè)Javadoc標(biāo)簽。2)錯(cuò)誤,不能工作(FIXME)(標(biāo)記人,標(biāo)記時(shí)間,[預(yù)計(jì)處理時(shí)間])在注釋中用FIXME標(biāo)記某代碼是錯(cuò)誤的,而且不能工作,需要及時(shí)糾正的情況。其他 【強(qiáng)制】在使用正則表達(dá)式時(shí),利用好其預(yù)編譯功能,可以有效加快正則匹配速度。說明:不要在方法體內(nèi)定義:Patternpattern=Ppile 【強(qiáng)制】velocity調(diào)用POJO類的屬性時(shí),建議直接使用屬POJO的getXxx(),如果是boolean基本數(shù)據(jù)類型變量(boolean命名不需要加is前綴)isXxx()方法。說明:注意如果是Boolean包裝類對(duì)象,優(yōu)先調(diào)用getXxx()的方法。 【強(qiáng)制】后臺(tái)輸送給頁面的變量必須加$!{var}——中間的感嘆號(hào)。說明:如果var等于null或者不存在,那么${var}會(huì)直接顯示在頁面上。 【強(qiáng)制】注意Math.random()這個(gè)方法返回是double類型,注意取值的范圍0≤x<1(能夠取到零值,注意除零異常),如果想獲取整數(shù)類型的隨機(jī)數(shù),不要將x放大10的若干倍然后取整,直接使用 Random對(duì)象的 nextInt或者nextLong方法。 【強(qiáng)制】獲取當(dāng)前毫秒數(shù)System.currentTimeMillis();而不是newDate().getTime();用System.nanoTime()的方式。在JDK8中,針對(duì)統(tǒng)計(jì)時(shí)間等場(chǎng)景,推薦使用Instant類?!就扑]】不要在視圖模板中加入任何復(fù)雜的邏輯。說明:根據(jù)MVC理論,視圖的職責(zé)是展示,不要搶模型和控制器的活。 【推薦】任何數(shù)據(jù)結(jié)構(gòu)的構(gòu)造或初始化,都應(yīng)指定大小,避免數(shù)據(jù)結(jié)構(gòu)無限增長(zhǎng)吃光內(nèi)存?!就扑]】及時(shí)清理不再使用的代碼段或配置信息。說明:對(duì)于垃圾代碼或過時(shí)配置,堅(jiān)決清理干凈,避免程序過度臃腫,代碼冗余。正例:對(duì)于暫時(shí)被注釋掉,后續(xù)可能恢復(fù)使用的代碼片斷,在注釋代碼上方,統(tǒng)一規(guī)定使用三個(gè)斜杠(///)來說明注釋掉代碼的理由。異常日志異常處理 Java的RuntimeException異常不應(yīng)該通過catch的方式來處理,比如:NullPointerException,IndexOutOfBoundsException等等。說明:無法通過預(yù)檢查的異常除外,比如,在解析字符串形式的數(shù)字時(shí),不得不通過catchNumberFormatException來實(shí)現(xiàn)。if(obj!=null){...}try{obj.method();}catch(NullPointerExceptione【強(qiáng)制】異常不要用來做流程控制,條件控制。說明:異常設(shè)計(jì)的初衷是解決程序運(yùn)行中的各種意外情況,且異常的處理效率比條件判斷方式要低很多。 【強(qiáng)制】catch時(shí)請(qǐng)分清穩(wěn)定代碼和非穩(wěn)定代碼,穩(wěn)定代碼指的是無論如何不會(huì)出錯(cuò)的代碼。對(duì)于非穩(wěn)定代碼的catch盡可能進(jìn)行區(qū)分異常類型,再做對(duì)應(yīng)的異常處理。說明:對(duì)大段代碼進(jìn)行try-catch,使程序無法根據(jù)不同的異常做出正確的應(yīng)激反應(yīng),也不利于定位問題,這是一種不負(fù)責(zé)任的表現(xiàn)。正例:用戶注冊(cè)的場(chǎng)景中,如果用戶輸入非法字符,或用戶名稱已存在,或用戶輸入密碼過于簡(jiǎn)單,在程序上作出分門別類的判斷,并提示給用戶。 【強(qiáng)制】捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請(qǐng)將該異常拋給它的調(diào)用者。最外層的業(yè)務(wù)使用者,必須處理異常,將其轉(zhuǎn)化為用戶可以理解的內(nèi)容。 【強(qiáng)制】有try塊放到了事務(wù)代碼中,catch異常后,如果需要回滾事務(wù),一定要注意手動(dòng)回滾事務(wù)。 【強(qiáng)制】finally塊必須對(duì)資源對(duì)象、流對(duì)象進(jìn)行關(guān)閉,有異常也要做try-catch。說明:如果JDK7及以上,可以使用try-with-resources方式?!緩?qiáng)制】不要在finally塊中使用return說明:finally塊中的return返回后方法結(jié)束執(zhí)行,不會(huì)再執(zhí)行try塊中的return語句。 【強(qiáng)制】捕獲異常與拋異常,必須是完全匹配,或者捕獲異常是拋異常的父類。說明:如果預(yù)期對(duì)方拋的是繡球,實(shí)際接到的是鉛球,就會(huì)產(chǎn)生意外情況。 【推薦】方法的返回值可以為null,不強(qiáng)制返回空集合,或者空對(duì)象等,必須添加注釋充分說明什么情況下會(huì)返回null值。說明:本手冊(cè)明確防止NPE是調(diào)用者的責(zé)任。即使被調(diào)用方法返回空集合或者空對(duì)象,對(duì)調(diào)用者來說,也并非高枕無憂,必須考慮到遠(yuǎn)程調(diào)用失敗、序列化失敗、運(yùn)行時(shí)異常等場(chǎng)景返回null的情況?!就扑]】防止NPE,是程序員的基本修養(yǎng),注意NPE產(chǎn)生的場(chǎng)景:返回類型為基本數(shù)據(jù)類型,return包裝數(shù)據(jù)類型的對(duì)象時(shí),自動(dòng)拆箱有可能產(chǎn)生NPE。反例:publicintf(){ returnInteger對(duì)象},如果為null,自動(dòng)解箱拋NPE。數(shù)據(jù)庫的查詢結(jié)果可能為null集合里的元素即使isNotEmpty,取出的數(shù)據(jù)元素也可能為null。遠(yuǎn)程調(diào)用返回對(duì)象時(shí),一律要求進(jìn)行空指針判斷,防止NPE。對(duì)于Session中獲取的數(shù)據(jù),建議NPE檢查,避免空指針。級(jí)聯(lián)調(diào)用obj.getA().getB().getC();一連串調(diào)用,易產(chǎn)生NPE。正例:使用JDK8的Optional類來防止NPE問題?!就扑]】定義時(shí)區(qū)分unchecked/checked異常,避免直接拋出newRuntimeException(),更不允許拋出Exception或者Throwable,應(yīng)使用有業(yè)務(wù)含義的自定義異常。推薦業(yè)界已定義過的自定義異常,如:DAOException/ServiceException等?!緟⒖肌繉?duì)于公司外的http/api開放接口必須使用“錯(cuò)誤碼”;而應(yīng)用內(nèi)部推薦異常拋出;跨應(yīng)用間RPC調(diào)用優(yōu)先考慮使用Result方式,封裝isSuccess()方法、“錯(cuò)誤碼”、“錯(cuò)誤簡(jiǎn)短信息”。說明:關(guān)于RPC方法返回方式使用Result方式的理由:使用拋異常返回方式,調(diào)用方如果沒有捕獲到就會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。如果不加棧信息,只是new自定義異常,加入自己的理解的errormessage,對(duì)于調(diào)用端解決問題的幫助不會(huì)太多。如果加了棧信息,在頻繁調(diào)用出錯(cuò)的情況下,數(shù)據(jù)序列化和傳輸?shù)男阅軗p耗也是問題?!緟⒖肌勘苊獬霈F(xiàn)重復(fù)的代碼(DontRepeatYourself)即DRY原則。說明:隨意復(fù)制和粘貼代碼,必然會(huì)導(dǎo)致代碼的重復(fù),在以后需要修改時(shí),需要修改所有的副本,容易遺漏。必要時(shí)抽取共性方法,或者抽象公共類,甚至是組件化。正例:一個(gè)類中有多個(gè)public方法,都需要進(jìn)行數(shù)行相同的參數(shù)校驗(yàn)操作,這個(gè)時(shí)候請(qǐng)抽?。簆rivatebooleancheckParam(DTOdto){...}數(shù)據(jù)庫建表規(guī)約 【強(qiáng)制】表名、字段名必須使用小寫字母或數(shù)字,禁止出現(xiàn)數(shù)字開頭,禁止兩個(gè)下劃線中間只出現(xiàn)數(shù)字。數(shù)據(jù)庫字段名的修改代價(jià)很大,因?yàn)闊o法進(jìn)行預(yù)發(fā)布,所以字段名稱需要慎重考慮。說明:MySQLWindows下不區(qū)分大小寫,但在Linux下默認(rèn)是區(qū)分大小寫。因此,數(shù)據(jù)庫名、表名、字段名,都不允許出現(xiàn)任何大寫字母,避免節(jié)外生枝。aliyun_adminrdc_configlevel3_nameAliyunAdminrdcConfiglevel_3_name【強(qiáng)制】表名不使用復(fù)數(shù)名詞。說明:表名應(yīng)該僅僅表示表里面的實(shí)體內(nèi)容,不應(yīng)該表示實(shí)體數(shù)量,對(duì)應(yīng)于DO類名也是單數(shù)形式,符合表達(dá)習(xí)慣。【強(qiáng)制】禁用保留字,如desc、range、match、delayed等?!緩?qiáng)制】主鍵索引名為pk_字段名;唯一索引名為uk_字段名;普通索引名則為idx_字段名。說明:pk_即primarykey;uk_即uniquekeyidx_即index的簡(jiǎn)稱。 【強(qiáng)制】如果存儲(chǔ)的字符串長(zhǎng)度幾乎相等,使用char定長(zhǎng)字符串類型。 【強(qiáng)制】varchar是可變長(zhǎng)字符串,不預(yù)先分配存儲(chǔ)空間,長(zhǎng)度不要超過5000,如果存儲(chǔ)長(zhǎng)度大于此值,定義字段類型text,獨(dú)立出來一張表,用主鍵來對(duì)應(yīng),避免影響其它字段索引效率。 【強(qiáng)制】表必備三字段:id,gmt_create,gmt_modified。說明:其中id必為主鍵,類型為bigintunsigned、單表1gmt_create,gmt_modified為datetime類型,前者現(xiàn)在時(shí)表示主動(dòng)創(chuàng)建,后者過去分詞表示被動(dòng)更新。 【推薦】表的命名最好是加上“業(yè)務(wù)名稱_表的作用”。alipay_task/force_project/trade_config【推薦】庫名與應(yīng)用名稱盡量一致。【推薦】如果修改字段含義或?qū)ψ侄伪硎镜臓顟B(tài)追加時(shí),需要及時(shí)更新字段注釋?!就扑]】字段允許適當(dāng)冗余,以提高查詢性能,但必須考慮數(shù)據(jù)一致。冗余字段應(yīng)遵循:不是頻繁修改的字段。不是varchar超長(zhǎng)字段,更不能是text字段。正例:商品類目名稱使用頻率高,字段長(zhǎng)度短,名稱基本一成不變,可在相關(guān)聯(lián)的表中冗余存儲(chǔ)類目名稱,避免關(guān)聯(lián)查詢?!緟⒖肌亢线m的字符存儲(chǔ)長(zhǎng)度,不但節(jié)約數(shù)據(jù)庫表空間、節(jié)約索引存儲(chǔ),更重要的是提升檢索速度。對(duì)象年齡區(qū)間類型對(duì)象年齡區(qū)間類型字節(jié)150歲之tinyintunsigned到255數(shù)百歲smallintunsigned到65535恐龍化數(shù)千萬年intunsigned到約42.9億太陽 50bigintunsigned到 的19次方索引規(guī)約 【強(qiáng)制】業(yè)務(wù)上具有唯一特性的字段,即使是多個(gè)字段的組合,也必須建成唯一索引。說明:不要以為唯一索引影響了insert速度,這個(gè)速度損耗可以忽略,但提高查找速度是明顯的;另外,即使在應(yīng)用層做了非常完善的校驗(yàn)控制,只要沒有唯一索引,根據(jù)墨菲定律,必然有臟數(shù)據(jù)產(chǎn)生。 【強(qiáng)制】超過三個(gè)表禁止join。需要join的字段,數(shù)據(jù)類型必須絕對(duì)一致;多表關(guān)聯(lián)查詢時(shí),保證被關(guān)聯(lián)的字段需要有索引。說明:即使雙表join也要注意表索引、SQL性能。 【強(qiáng)制在varchar字段上建立索引時(shí)必須指定索引長(zhǎng)度,沒必要對(duì)全字段建立索引, 根據(jù)實(shí)際文本區(qū)分度決定索引長(zhǎng)度即可。說明:索引的長(zhǎng)度與區(qū)分度是一對(duì)矛盾體,一般對(duì)字符串類型數(shù)據(jù),長(zhǎng)度為20的索引,區(qū)分度會(huì)高達(dá)90%以上,可以使用count(distinctleft(列名,索引長(zhǎng)度))/count(*)的區(qū)分度來確定。 【推薦】如果有orderby的場(chǎng)景,請(qǐng)注意利用索引的有序性。orderby最后的字段是組合索引的一部分,并且放在索引組合順序的最后,避免出現(xiàn)file_sort的情況,影響查詢性能。wherea=?andb=?orderbyc;索引:a_b_c反例:索引中有范圍查找,那么索引有序性無法利用,如:WHEREa>10ORDERBYb;索引a_b無法排序?!就扑]】利用覆蓋索引來進(jìn)行查詢操作,避免回表。說明:如果一本書需要知道第11章是什么標(biāo)題,會(huì)翻開第11章對(duì)應(yīng)的那一頁嗎?目錄瀏覽一下就好,這個(gè)目錄就是起到覆蓋索引的作用。正例:能夠建立索引的種類分為主鍵索引、唯一索引、普通索引三種,而覆蓋索引只是一種查詢的一種效果,用explain的結(jié)extra列會(huì)出現(xiàn):usingindex【推薦】利用延遲關(guān)聯(lián)或者子查詢優(yōu)化超多分頁場(chǎng)景。說明:MySQL并不是跳過offset行,而是取offset+N行,然后返回放棄前offset行,返回N行,那當(dāng)offset特別大的時(shí)候,效率就非常的低下,要么控制返回的總頁數(shù),要么對(duì)超過特定閾值的頁數(shù)進(jìn)行SQL改寫。正例:先快速定位需要獲取的id段,然后再關(guān)聯(lián):SELECTa.*FROM表1a,(selectidfrom表1where條件LIMIT100000,20)bwherea.id=b.id 【推薦】SQL性能優(yōu)化的目標(biāo):至少要達(dá)到range級(jí)別,要求是ref級(jí)別,如果可以是consts最好。說明:consts單表中最多只有一個(gè)匹配行(主鍵或者唯一索引),在優(yōu)化階段即可讀取到數(shù)據(jù)。ref指的是使用普通的索引(normalindex)3)range對(duì)索引進(jìn)行范圍檢索。反例:explain表的結(jié)果,type=index,索引物理文件全掃描,速度非常慢,這個(gè)index級(jí)別比較range還低,與全表掃描是小巫見大巫?!就扑]】建組合索引的時(shí)候,區(qū)分度最高的在最左邊。正例:如果 wherea=?andb=?,如果 a列的幾乎接近于唯一值,那么只需要單建idx_a索引即可。說明:存在非等號(hào)和等號(hào)混合時(shí),在建索引時(shí),請(qǐng)把等號(hào)條件的列前置。如:wherec>?andd=?那么即使c的區(qū)分度更高,也必須把d放在索引的最前列,即索引idx_d_c。【推薦】防止因字段類型不同造成的隱式轉(zhuǎn)換,導(dǎo)致索引失效?!緟⒖肌縿?chuàng)建索引時(shí)避免有如下極端誤解:寧濫勿缺。認(rèn)為一個(gè)查詢就需要建一個(gè)索引。寧缺勿濫。認(rèn)為索引會(huì)消耗空間、嚴(yán)重拖慢更新和新增速度。抵制惟一索引。認(rèn)為業(yè)務(wù)的惟一性一律需要在應(yīng)用層通過“先查后插”方式解決。SQL 【強(qiáng)制】不要使用 count(列名)或 count(常量)來替代count(*)count(*是SQL92定義的標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語法,跟數(shù)據(jù)庫無關(guān),跟NULL和非NULL無關(guān)。說明:count(*)會(huì)統(tǒng)計(jì)值為NULL的行,而count(列名)不會(huì)統(tǒng)計(jì)此列為NULL值的行。 【強(qiáng)制】count(distinctcol)計(jì)算該列除NULL之外的不重復(fù)行數(shù),注意count(distinctcol1,col2)如果其中一列全為NULL,那么即使另一列有不同的值,也返回為0。 【強(qiáng)制】當(dāng)某一列的值全是NULL時(shí),count(col)的返回結(jié)果為0,但sum(col)的返回結(jié)果為NULL,因此使用sum()時(shí)需注意NPE問題。正例:可以使用如下方式來避免sum的NPE問題:SELECTIF(ISNULL(SUM(g)),0,SUM(g))FROMtable; 【強(qiáng)制】使用ISNULL()來判斷是否為NULL值。NULL與任何值的直接比較都為NULL。NULL<>NULL的返回結(jié)果是NULL,而不是falseNULL=NULL的返回結(jié)果是NULL,而不是trueNULL<>1的返回結(jié)果是NULL,而不是true 【強(qiáng)制】在代碼中寫分頁查詢邏輯時(shí),若count為0應(yīng)直接返回,避免執(zhí)行后面的分頁語句。 【強(qiáng)制】不得使用外鍵與級(jí)聯(lián),一切外鍵概念必須在應(yīng)用層解決。說明:以學(xué)生和成績(jī)的關(guān)系為例,學(xué)生表中的student_id是主鍵,那么成績(jī)表中的student_id則為外鍵。如果更新學(xué)生表中的student_id,同時(shí)觸發(fā)成績(jī)表中的student_id更新,即為級(jí)聯(lián)更新。外鍵與級(jí)聯(lián)更新適用于單機(jī)低并發(fā),不適合分布式、高并發(fā)集群;級(jí)聯(lián)更新是強(qiáng)阻塞,存在數(shù)據(jù)庫更新風(fēng)暴的風(fēng)險(xiǎn);外鍵影響數(shù)據(jù)庫的插入速度。 【強(qiáng)制】禁止使用存儲(chǔ)過程,存儲(chǔ)過程難以調(diào)試和擴(kuò)展,更沒有移植性。 【強(qiáng)制】數(shù)據(jù)訂正(特別是刪除、修改記錄操作)先select,避免出現(xiàn)誤刪除,確認(rèn)無誤才能執(zhí)行更新語句。 【推薦】in操作能避免則避免,若實(shí)在避免不了,需要仔細(xì)評(píng)估in后邊的集合元素?cái)?shù)量,控制在1000個(gè)之內(nèi)。工程結(jié)構(gòu)應(yīng)用分層 【推薦】圖中默認(rèn)上層依賴于下層,箭頭關(guān)系表示可直接依賴,Web于Service層,依此類推:開放接口層:可直接封裝Service方法暴露成RPC接口;通過Web封裝成http接口;進(jìn)行網(wǎng)關(guān)安全控制、流量控制等。終端顯示層:各個(gè)端的模板渲染并執(zhí)行顯示的層。當(dāng)前主要是velocity渲染,JS渲染,JSP渲染,移動(dòng)端展示等。Web層:主要是對(duì)訪問控制進(jìn)行轉(zhuǎn)發(fā),各類基本參數(shù)校驗(yàn),或者不復(fù)用的業(yè)務(wù)簡(jiǎn)單處理等。Service層:相對(duì)具體的業(yè)務(wù)邏輯服務(wù)層。Manager層:通用業(yè)務(wù)處理層,它有如下特征:對(duì)第三方平臺(tái)封裝的層,預(yù)處理返回結(jié)果及轉(zhuǎn)化異常信息; Service層通用能力的下沉,如緩存方案、中間件通用處理;與DAO層交互,對(duì)多個(gè)DAO的組合復(fù)用。DAO層:數(shù)據(jù)訪問層,與底層MySQL、Oracle、Hbase等進(jìn)行數(shù)據(jù)交互。外部接口或第三方平臺(tái):包括其它部門RPC開放接口,基礎(chǔ)平臺(tái),其它公司的HTTP接口。【參考】(分層異常處理規(guī)約)在DAO層,產(chǎn)生的異常類型有很多,無法用細(xì)粒度的異常進(jìn)行 catch,使用catch(Exceptione)方式,并thrownewDAOException(e),不需要打印日志,因?yàn)槿罩驹贛anager/Service層一定需要捕獲并打印到日志文件中去,如果同臺(tái)服務(wù)器再打日志,浪費(fèi)性能和存儲(chǔ)在Service層出現(xiàn)異常時(shí)必須記錄出錯(cuò)日志到磁盤,盡可能帶上參數(shù)信息,相當(dāng)于保護(hù)案發(fā)現(xiàn)場(chǎng)。如果Manager層與Service同機(jī)部署,日志方式與DAO層處理一致,如果是單獨(dú)部署,則采用與Service一致的處理方式。Web層絕不應(yīng)該繼續(xù)往上拋異常,因?yàn)橐呀?jīng)處于頂層,如果意識(shí)到這個(gè)異常將導(dǎo)致頁面無法正常渲染,那么就應(yīng)該直接跳轉(zhuǎn)到友好錯(cuò)誤頁面,加上用戶容易理解的錯(cuò)誤提示信息。開放接口層要將異常處理成錯(cuò)誤碼和錯(cuò)誤信息方式返回?!緟⒖肌糠謱宇I(lǐng)域模型規(guī)約:DO(DataObject):此對(duì)象與數(shù)據(jù)庫表結(jié)構(gòu)一一對(duì)應(yīng),通過DAO層向上傳輸數(shù)據(jù)源對(duì)象。DTO(DataTransferObject)Service或Manager向外傳輸?shù)膶?duì)象。BO(BusinessObject):業(yè)務(wù)對(duì)象,由Service層輸出的封裝業(yè)務(wù)邏輯的對(duì)象。AO(ApplicationObject)Web層與Service層之間抽象的復(fù)用對(duì)象模型,極為貼近展示層,復(fù)用度不高。VO(ViewObject):顯示層對(duì)象,通常是Web向模板渲染引擎層傳輸?shù)膶?duì)象。Query:數(shù)據(jù)查詢對(duì)象,各層接收上層的查詢請(qǐng)求。注意超過2個(gè)參數(shù)的查詢封裝,禁止使用Map類來傳輸。二方庫依賴【強(qiáng)制】定義GAV遵從以下規(guī)則:1) GroupIDcom.{公司/BU}.業(yè)務(wù)線[.子業(yè)務(wù)線],最多4級(jí)。 /BU} alibaba/tao
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 餐飲用地合同范本
- 合同違約寫協(xié)議
- 合作運(yùn)輸合同范本
- 中醫(yī)護(hù)理學(xué)基礎(chǔ)課件
- 心電圖護(hù)理中的虛擬現(xiàn)實(shí)技術(shù)應(yīng)用
- 護(hù)理管理與實(shí)踐領(lǐng)導(dǎo)力
- 痔瘡護(hù)理中的飲食禁忌
- 2025年安防設(shè)備租賃合同(商業(yè)街)
- 土壤養(yǎng)分傳感技術(shù)
- 2025年電池管理系統(tǒng)通信容錯(cuò)機(jī)制
- 直播間陪跑合同范本
- 如何樹立消防員榮譽(yù)觀
- 2026中國高校實(shí)驗(yàn)室危險(xiǎn)品智能管理平臺(tái)市場(chǎng)滲透分析報(bào)告
- 深圳市龍崗區(qū)2025年生物高一上期末調(diào)研模擬試題含解析
- (2025年)法院聘用書記員試題及答案
- 具身智能+醫(yī)療康復(fù)中多模態(tài)感知與自適應(yīng)訓(xùn)練系統(tǒng)研究報(bào)告
- 廣東省深圳市寶安區(qū)2026屆高一上生物期末聯(lián)考試題含解析
- ISO14644-5-2025潔凈室及相關(guān)受控環(huán)境-第5部分運(yùn)行中文版
- 2025年國家開放大學(xué)《法學(xué)導(dǎo)論》期末考試備考題庫及答案解析
- 物業(yè)公司動(dòng)火安全管理制度
- 幕墻創(chuàng)優(yōu)工程匯報(bào)材料
評(píng)論
0/150
提交評(píng)論