![APP安全編碼規(guī)范_第1頁(yè)](http://file4.renrendoc.com/view14/M09/06/34/wKhkGWaVwxeAeUuyAAA0yknXiqM323.jpg)
![APP安全編碼規(guī)范_第2頁(yè)](http://file4.renrendoc.com/view14/M09/06/34/wKhkGWaVwxeAeUuyAAA0yknXiqM3232.jpg)
![APP安全編碼規(guī)范_第3頁(yè)](http://file4.renrendoc.com/view14/M09/06/34/wKhkGWaVwxeAeUuyAAA0yknXiqM3233.jpg)
![APP安全編碼規(guī)范_第4頁(yè)](http://file4.renrendoc.com/view14/M09/06/34/wKhkGWaVwxeAeUuyAAA0yknXiqM3234.jpg)
![APP安全編碼規(guī)范_第5頁(yè)](http://file4.renrendoc.com/view14/M09/06/34/wKhkGWaVwxeAeUuyAAA0yknXiqM3235.jpg)
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
編碼規(guī)范XX科技股份有限公司編制目錄一、編程規(guī)約 4(一) 命名風(fēng)格 4(二) 常量定義 8 代碼格式 9 13 集合處理 19 并發(fā)處理 24 控制語(yǔ)句 30 注釋規(guī)約 34 其它 35二、異常日志 37 異常處理 37 日志規(guī)約 40三、單元測(cè)試 42四、安全規(guī)約 44五、MySQL數(shù)據(jù)庫(kù) 45建表規(guī)約 45索引規(guī)約 47SQL語(yǔ)句 49ORM映射 50六、工程結(jié)構(gòu) 51應(yīng)用分層 52二方庫(kù)依賴 53(三)服務(wù)器 55七、設(shè)計(jì)規(guī)約 56附1:專有名詞解釋 60PAGEPAGE19一、編程規(guī)約(一)命名風(fēng)格1.【強(qiáng)制】代碼中的命名均不能以下劃線或美元符號(hào)開始,也不能以下劃線或美元符號(hào)結(jié)束。反例:_name/name/$name/name_/name$/name 2.【強(qiáng)制】代碼中的命名嚴(yán)禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。說(shuō)明:正確的英文拼寫和語(yǔ)法可以讓閱讀者易于理解,避免歧義。注意,純拼音命名方式更要避免采用。正例:renminbi/alibaba/taobao/youku/hangzhou等國(guó)際通用的名稱,可視同英文。反例:DaZhePromotion[打折]/getPingfenByName()[評(píng)分]/int某變量=3【強(qiáng)制】類名使用UpperCamelCase風(fēng)格,但以下情形例外:DO/BO/DTO/VO/AO/PO/UID等。正例:JavaServerlessPlatform/UserDO/XmlService/TcpUdpDeal/TaPromotion反例:javaserverlessplatform/UserDo/XMLService/TCPUDPDeal/TAPromotion4.【強(qiáng)制】方法名、參數(shù)名、成員變量、局部變量都統(tǒng)一使用lowerCamelCase風(fēng)格,必須遵從駝峰形式。正例:localValue/getHttpMessage()/inputUserId5.【強(qiáng)制】常量命名全部大寫,單詞間用下劃線隔開,力求語(yǔ)義表達(dá)完整清楚,不要嫌名字長(zhǎng)。正例:MAX_STOCK_COUNT/CACHE_EXPIRED_TIME反例:MAX_COUNT/EXPIRED_TIME6.【強(qiáng)制】抽象類命名使用Abstract或Base開頭;異常類命名使用Exception結(jié)尾;測(cè)試類命名以它要測(cè)試的類的名稱開始,以Test結(jié)尾。7.【強(qiáng)制】類型與中括號(hào)緊挨相連來(lái)表示數(shù)組。正例:定義整形數(shù)組int[]arrayDemo;反例:在main參數(shù)中,使用Stringargs[]來(lái)定義。8.【強(qiáng)制】POJO類中布爾類型變量都不要加is前綴,否則部分框架解析會(huì)引起序列化錯(cuò)誤。說(shuō)明:在本文MySQL規(guī)約中的建表約定第一條,表達(dá)是與否的值采用is_xxx的命名方式,所以,需要在<resultMap>設(shè)置從is_xxx到xxx的映射關(guān)系。反例:定義為基本數(shù)據(jù)類型BooleanisDeleted的屬性,它的方法也是isDeleted(),RPC框架在反向解析的時(shí)候,“誤以為”對(duì)應(yīng)的屬性名稱是deleted,導(dǎo)致屬性獲取不到,進(jìn)而拋出異常。9.【強(qiáng)制】包名統(tǒng)一使用小寫,點(diǎn)分隔符之間有且僅有一個(gè)自然語(yǔ)義的英語(yǔ)單詞。包名統(tǒng)一使用單數(shù)形式,但是類名如果有復(fù)數(shù)含義,類名可以使用復(fù)數(shù)形式。正例:應(yīng)用工具類包名為com.alibaba.ai.util、類名為MessageUtils(此規(guī)則參考spring的框架結(jié)構(gòu))10.【強(qiáng)制】避免在子父類的成員變量之間、或者不同代碼塊的局部變量之間采用完全相同的命名,使可讀性降低。說(shuō)明:子類、父類成員變量名相同,即使是public類型的變量也是能夠通過(guò)編譯,而局部變量在同一方法內(nèi)的不同代碼塊中同名也是合法的,但是要避免使用。對(duì)于非setter/getter的參數(shù)名稱也要避免與成員變量名稱相同。反例:publicclassConfusingName{publicintage;//非setter/getter的參數(shù)名稱,不允許與本類成員變量同名publicvoidgetData(Stringalibaba){if(condition){finalintmoney=531;//...}for(inti=0;i<10;i++){//在同一方法體中,不允許與其它代碼塊中的money命名相同finalintmoney=615;//...}}}classSonextendsConfusingName{//不允許與父類的成員變量名稱相同publicintage;}11.【強(qiáng)制】杜絕完全不規(guī)范的縮寫,避免望文不知義。反例:AbstractClass“縮寫”命名成AbsClass;condition“縮寫”命名成condi,此類隨意縮寫嚴(yán)重降低了代碼的可閱讀性。12.【推薦】為了達(dá)到代碼自解釋的目標(biāo),任何自定義編程元素在命名時(shí),使用盡量完整的單詞組合來(lái)表達(dá)其意。正例:在JDK中,表達(dá)原子更新的類名為:AtomicReferenceFieldUpdater。反例:inta的隨意命名方式。13.【推薦】在常量與變量的命名時(shí),表示類型的名詞放在詞尾,以提升辨識(shí)度。正例:startTime/workQueue/nameList/TERMINATED_THREAD_COUNT反例:startedAt/QueueOfWork/listName/COUNT_TERMINATED_THREAD14.【推薦】如果模塊、接口、類、方法使用了設(shè)計(jì)模式,在命名時(shí)需體現(xiàn)出具體模式。說(shuō)明:將設(shè)計(jì)模式體現(xiàn)在名字中,有利于閱讀者快速理解架構(gòu)設(shè)計(jì)理念正例:publicclassOrderFactory;publicclassLoginProxy;publicclassResourceObserver;15.【推薦】接口類中的方法和屬性不要加任何修飾符號(hào)(public也不要加),保持代碼的簡(jiǎn)潔性,并加上有效的Javadoc注釋。盡量不要在接口里定義變量,如果一定要定義變量,肯定是與接口方法相關(guān),并且是整個(gè)應(yīng)用的基礎(chǔ)常量。正例:接口方法簽名voidcommit();接口基礎(chǔ)常量StringCOMPANY="alibaba";反例:接口方法定義publicabstractvoidf();說(shuō)明:JDK8中接口允許有默認(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的理念,暴露出來(lái)的服務(wù)一定是接口,內(nèi)部的實(shí)現(xiàn)類用Impl的后綴與接口區(qū)別。正例:CacheServiceImpl實(shí)現(xiàn)CacheService接口。2)【推薦】如果是形容能力的接口名稱,取對(duì)應(yīng)的形容詞為接口名(通常是–able的形容詞)。正例:AbstractTranslator實(shí)現(xiàn)Translatable接口。17.【參考】枚舉類名帶上Enum后綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開。說(shuō)明:枚舉其實(shí)就是特殊的類,域成員均為常量,且構(gòu)造方法被默認(rèn)強(qiáng)制是私有。正例:枚舉名字為ProcessStatusEnum的成員名稱:SUCCESS/UNKNOWN_REASON。18.【參考】各層命名規(guī)約:Service/DAO層方法命名規(guī)約1)獲取單個(gè)對(duì)象的方法用get做前綴。2)獲取多個(gè)對(duì)象的方法用list做前綴,復(fù)數(shù)形式結(jié)尾如:listObjects。3)獲取統(tǒng)計(jì)值的方法用count做前綴。4)插入的方法用save/insert做前綴。5)刪除的方法用remove/delete做前綴。6)修改的方法用update做前綴。B)領(lǐng)域模型命名規(guī)約1)數(shù)據(jù)對(duì)象:xxxDO,xxx即為數(shù)據(jù)表名。2)數(shù)據(jù)傳輸對(duì)象:xxxDTO,xxx為業(yè)務(wù)領(lǐng)域相關(guān)的名稱。3)展示對(duì)象:xxxVO,xxx一般為網(wǎng)頁(yè)名稱。4)POJO是DO/DTO/BO/VO的統(tǒng)稱,禁止命名成xxxPOJO。(二)常量定義1.【強(qiáng)制】不允許任何魔法值(即未經(jīng)預(yù)先定義的常量)直接出現(xiàn)在代碼中。反例:Stringkey="Id#taobao_"+tradeId;cache.put(key,value);//緩存get時(shí),由于在代碼復(fù)制時(shí),漏掉下劃線,導(dǎo)致緩存擊穿而出現(xiàn)問(wèn)題2.【強(qiáng)制】在long或者Long賦值時(shí),數(shù)值后使用大寫的L,不能是小寫的l,小寫容易跟數(shù)字1混淆,造成誤解。說(shuō)明:Longa=2l;寫的是數(shù)字的21,還是Long2。3.【推薦】不要使用一個(gè)常量類維護(hù)所有常量,要按常量功能進(jìn)行歸類,分開維護(hù)。說(shuō)明:大而全的常量類,雜亂無(wú)章,使用查找功能才能定位到修改的常量,不利于理解和維護(hù)。正例:緩存相關(guān)常量放在類CacheConsts下;系統(tǒng)配置相關(guān)常量放在類ConfigConsts下。4.【推薦】常量的復(fù)用層次有五層:跨應(yīng)用共享常量、應(yīng)用內(nèi)共享常量、子工程內(nèi)共享常量、包內(nèi)共享常量、類內(nèi)共享常量。1)跨應(yīng)用共享常量:放置在二方庫(kù)中,通常是client.jar中的constant目錄下。2)應(yīng)用內(nèi)共享常量:放置在一方庫(kù)中,通常是子模塊中的constant目錄下。反例:易懂變量也要統(tǒng)一定義成應(yīng)用內(nèi)共享常量,兩位工程師在兩個(gè)類中分別定義了“YES”的變量:類A中:publicstaticfinalStringYES="yes";類B中:publicstaticfinalStringYES="y";A.YES.equals(B.YES),預(yù)期是true,但實(shí)際返回為false,導(dǎo)致線上問(wèn)題。3)子工程內(nèi)部共享常量:即在當(dāng)前子工程的constant目錄下。4)包內(nèi)共享常量:即在當(dāng)前包下單獨(dú)的constant目錄下。5)類內(nèi)共享常量:直接在類內(nèi)部privatestaticfinal定義。5.【推薦】如果變量值僅在一個(gè)固定范圍內(nèi)變化用enum類型來(lái)定義。說(shuō)明:如果存在名稱之外的延伸屬性應(yīng)使用enum類型,下面正例中的數(shù)字就是延伸信息,表示一年中的第幾個(gè)季節(jié)。正例:publicenumSeasonEnum{SPRING(1),SUMMER(2),AUTUMN(3),WINTER(4);privateintseq;SeasonEnum(intseq){this.seq=seq;}publicintgetSeq(){returnseq;}}(三) 代碼格式1.【強(qiáng)制】如果是大括號(hào)內(nèi)為空,則簡(jiǎn)潔地寫成{}即可,大括號(hào)中間無(wú)需換行和空格;如果是非空代碼塊則:1)左大括號(hào)前不換行。2)左大括號(hào)后換行。3)右大括號(hào)前換行。4)右大括號(hào)后還有else等代碼則不換行;表示終止的右大括號(hào)后必須換行。2.【強(qiáng)制】左小括號(hào)和字符之間不出現(xiàn)空格;同樣,右小括號(hào)和字符之間也不出現(xiàn)空格;而左大括號(hào)前需要空格。詳見第5條下方正例提示。反例:if(空格a==b空格)3.【強(qiáng)制】if/for/while/switch/do等保留字與括號(hào)之間都必須加空格。4.【強(qiáng)制】任何二目、三目運(yùn)算符的左右兩邊都需要加一個(gè)空格。說(shuō)明:運(yùn)算符包括賦值運(yùn)算符=、邏輯運(yùn)算符&&、加減乘除符號(hào)等。5.【強(qiáng)制】采用4個(gè)空格縮進(jìn),禁止使用tab字符。說(shuō)明:如果使用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=0;//關(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){//右大括號(hào)前換行,右大括號(hào)后有else,不用換行}else{System.out.println("ok");//在右大括號(hào)后直接結(jié)束,則必須換行}}6.【強(qiáng)制】注釋的雙斜線與注釋內(nèi)容之間有且僅有一個(gè)空格。正例://這是示例注釋,請(qǐng)注意在雙斜線之后有一個(gè)空格Stringparam=newString();7.【強(qiáng)制】在進(jìn)行類型強(qiáng)制轉(zhuǎn)換時(shí),右括號(hào)與強(qiáng)制轉(zhuǎn)換值之間不需要任何空格隔開。正例:longfirst=1000000000000L;intsecond=(int)first+2;8.【強(qiáng)制】單行字符數(shù)限制不超過(guò)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)前不要換行,見反例。正例:StringBuildersb=newStringBuilder();//超過(guò)120個(gè)字符的情況下,換行縮進(jìn)4個(gè)空格,點(diǎn)號(hào)和方法名稱一起換行sb.append("Jack").append("Ma")append("alibaba")append("alibaba")append("alibaba");反例:StringBuildersb=newStringBuilder();//超過(guò)120個(gè)字符的情況下,不要在括號(hào)前換行sb.append("Jack").append("Ma")...append("alibaba");//參數(shù)很多的方法調(diào)用可能超過(guò)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的textfileencoding設(shè)置為UTF-8;IDE中文件的換行符使用Unix格式,不要使用Windows格式。11.【推薦】單個(gè)方法的總行數(shù)不超過(guò)80行。說(shuō)明:除注釋之外的方法簽名、左右大括號(hào)、方法內(nèi)代碼、空行、回車及任何不可見字符的總行數(shù)不超過(guò)80行。正例:代碼邏輯分清紅花和綠葉,個(gè)性和共性,綠葉邏輯單獨(dú)出來(lái)成為額外方法,使主干代碼更加清晰;共性邏輯抽取成為共性方法,便于復(fù)用和維護(hù)。12.【推薦】沒有必要增加若干空格來(lái)使變量的賦值等號(hào)與上一行對(duì)應(yīng)位置的等號(hào)對(duì)齊。正例:intone=1;longtwo=2L;floatthree=3F;StringBuildersb=newStringBuilder();說(shuō)明:增加sb這個(gè)變量,如果需要對(duì)齊,則給one、two、three都要增加幾個(gè)空格,在變量比較多的情況下,是非常累贅的事情。13.【推薦】不同邏輯、不同語(yǔ)義、不同業(yè)務(wù)的代碼之間插入一個(gè)空行分隔開來(lái)以提升可讀性。說(shuō)明:任何情形,沒有必要插入多個(gè)空行進(jìn)行隔開。(四) OOP規(guī)約1.【強(qiáng)制】避免通過(guò)一個(gè)類的對(duì)象引用訪問(wèn)此類的靜態(tài)變量或靜態(tài)方法,無(wú)謂增加編譯器解析成本,直接用類名來(lái)訪問(wèn)即可。2.【強(qiáng)制】所有的覆寫方法,必須加@Override注解。說(shuō)明:getObject()與get0bject()的問(wèn)題。一個(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ù),避免使用Object。說(shuō)明:可變參數(shù)必須放置在參數(shù)列表的最后。(提倡同學(xué)們盡量不用可變參數(shù)編程)正例:publicList<User>listUsers(Stringtype,Long...ids){...}4.【強(qiáng)制】外部正在調(diào)用或者二方庫(kù)依賴的接口,不允許修改方法簽名,避免對(duì)接口調(diào)用方產(chǎn)生影響。接口過(guò)時(shí)必須加@Deprecated注解,并清晰地說(shuō)明采用的新接口或者新服務(wù)是什么。5.【強(qiáng)制】不能使用過(guò)時(shí)的類或方法。說(shuō)明:.URLDecoder中的方法decode(StringencodeStr)這個(gè)方法已經(jīng)過(guò)時(shí),應(yīng)該使用雙參數(shù)decode(Stringsource,Stringencode)。接口提供方既然明確是過(guò)時(shí)接口,那么有義務(wù)同時(shí)提供新的接口;作為調(diào)用方來(lái)說(shuō),有義務(wù)去考證過(guò)時(shí)方法的新實(shí)現(xiàn)是什么。6.【強(qiáng)制】Object的equals方法容易拋空指針異常,應(yīng)使用常量或確定有值的對(duì)象來(lái)調(diào)用equals。說(shuō)明:推薦使用java.util.Objects#equals(JDK7引入的工具類)。7.【強(qiáng)制】所有整型包裝類對(duì)象之間值的比較,全部使用equals方法比較。說(shuō)明:對(duì)于Integervar=?在-128至范圍內(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)行判斷。8.【強(qiáng)制】浮點(diǎn)數(shù)之間的等值判斷,基本數(shù)據(jù)類型不能用==來(lái)比較,包裝數(shù)據(jù)類型不能用equals來(lái)判斷。說(shuō)明:浮點(diǎn)數(shù)采用“尾數(shù)+階碼”的編碼方式,類似于科學(xué)計(jì)數(shù)法的“有效數(shù)字+指數(shù)”的表示方式。二進(jìn)制無(wú)法精確表示大部分的十進(jìn)制小數(shù),具體原理參考《碼出高效》。反例:floata=1.0f-0.9f;floatb=0.9f-0.8f;if(a==b){//預(yù)期進(jìn)入此代碼快,執(zhí)行其它業(yè)務(wù)邏輯//但事實(shí)上a==b的結(jié)果為false}Floatx=Float.valueOf(a);Floaty=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)為是相等的。floata=1.0f-0.9f;floatb=0.9f-0.8f;floatdiff=1e-6f;if(Math.abs(a-b)<diff){}(2)使用BigDecimal來(lái)定義值,再進(jìn)行浮點(diǎn)數(shù)的運(yùn)算操作。BigDecimala=newBigDecimal("1.0");BigDecimalb=newBigDecimal("0.9");BigDecimalc=newBigDecimal("0.8");BigDecimalx=a.subtract(b);BigDecimaly=b.subtract(c);if(x.equals(y)){}9.【強(qiáng)制】定義數(shù)據(jù)對(duì)象DO類時(shí),屬性類型要與數(shù)據(jù)庫(kù)字段類型相匹配。正例:數(shù)據(jù)庫(kù)字段的bigint必須與類屬性的Long類型相對(duì)應(yīng)。反例:某個(gè)案例的數(shù)據(jù)庫(kù)表id字段定義類型bigintunsigned,實(shí)際類對(duì)象屬性為Integer,隨著id越來(lái)越大,超過(guò)Integer的表示范圍而溢出成為負(fù)數(shù)。10.【強(qiáng)制】為了防止精度損失,禁止使用構(gòu)造方法BigDecimal(double)的方式把double值轉(zhuǎn)化為BigDecimal對(duì)象。說(shuō)明:BigDecimal(double)存在精度損失風(fēng)險(xiǎn),在精確計(jì)算或值比較的場(chǎng)景中可能會(huì)導(dǎo)致業(yè)務(wù)邏輯異常。如:BigDecimalg=newBigDecimal(0.1f);實(shí)際的存儲(chǔ)值為:0.10000000149正例:優(yōu)先推薦入?yún)镾tring的構(gòu)造方法,或使用BigDecimal的valueOf方法,此方法內(nèi)部其實(shí)執(zhí)行了Double的toString,而Double的toString按double的實(shí)際能表達(dá)的精度對(duì)尾數(shù)進(jìn)行了截?cái)?。BigDecimalrecommend1=newBigDecimal("0.1");BigDecimalrecommend2=BigDecimal.valueOf(0.1);11.關(guān)于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標(biāo)準(zhǔn)如下:1)【強(qiáng)制】所有的POJO類屬性必須使用包裝數(shù)據(jù)類型。2)【強(qiáng)制】RPC方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型。3)【推薦】所有的局部變量使用基本數(shù)據(jù)類型。說(shuō)明:POJO類屬性沒有初值是提醒使用者在需要使用時(shí),必須自己顯式地進(jìn)行賦值,任何NPE問(wèn)題,或者入庫(kù)檢查,都由使用者來(lái)保證。正例:數(shù)據(jù)庫(kù)的查詢結(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í),返回的是默認(rèn)值,頁(yè)面顯示為0%,這是不合理的,應(yīng)該顯示成中劃線。所以包裝數(shù)據(jù)類型的null值,能夠表示額外的信息,如:遠(yuǎn)程調(diào)用失敗,異常退出。12.【強(qiáng)制】定義DO/DTO/VO等POJO類時(shí),不要設(shè)定任何屬性默認(rèn)值。反例:POJO類的createTime默認(rèn)值為newDate(),但是這個(gè)屬性在數(shù)據(jù)提取時(shí)并沒有置入具體值,在更新其它字段時(shí)又附帶更新了此字段,導(dǎo)致創(chuàng)建時(shí)間被修改成當(dāng)前時(shí)間。13.【強(qiáng)制】序列化類新增屬性時(shí),請(qǐng)不要修改serialVersionUID字段,避免反序列失??;如果完全不兼容升級(jí),避免反序列化混亂,那么請(qǐng)修改serialVersionUID值。說(shuō)明:注意serialVersionUID不一致會(huì)拋出序列化運(yùn)行時(shí)異常。14.【強(qiáng)制】構(gòu)造方法里面禁止加入任何業(yè)務(wù)邏輯,如果有初始化邏輯,請(qǐng)放在init方法中。15.【強(qiáng)制】POJO類必須寫toString方法。使用IDE中的工具:source>generatetoString時(shí),如果繼承了另一個(gè)POJO類,注意在前面加一下super.toString。說(shuō)明:在方法執(zhí)行拋出異常時(shí),可以直接調(diào)用POJO的toString()方法打印其屬性值,便于排查問(wèn)題。16.【強(qiáng)制】禁止在POJO類中,同時(shí)存在對(duì)應(yīng)屬性xxx的isXxx()和getXxx()方法。說(shuō)明:框架在調(diào)用屬性xxx的提取方法時(shí),并不能確定哪個(gè)方法一定是被優(yōu)先調(diào)用到。17.【推薦】使用索引訪問(wèn)用String的split方法得到的數(shù)組時(shí),需做最后一個(gè)分隔符后有無(wú)內(nèi)容的檢查,否則會(huì)有拋IndexOutOfBoundsException的風(fēng)險(xiǎn)。說(shuō)明:Stringstr="a,b,c,,";String[]ary=str.split(",");//預(yù)期大于3,結(jié)果是318.【推薦】當(dāng)一個(gè)類有多個(gè)構(gòu)造方法,或者多個(gè)同名方法,這些方法應(yīng)該按順序放置在一起,便于閱讀,此條規(guī)則優(yōu)先于下一條。19.【推薦】類內(nèi)方法定義的順序依次是:公有方法或保護(hù)方法>私有方法>getter/setter方法。說(shuō)明:公有方法是類的調(diào)用者和維護(hù)者最關(guān)心的方法,首屏展示最好;保護(hù)方法雖然只是子類關(guān)心,也可能是“模板設(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ù)邏輯,增加排查問(wèn)題的難度。反例:publicIntegergetData(){if(condition){returnthis.data+100;}else{returnthis.data-100;}}21.【推薦】循環(huán)體內(nèi),字符串的連接方式,使用StringBuilder的append方法進(jìn)行擴(kuò)展。說(shuō)明:下例中,反編譯出的字節(jié)碼文件顯示每次循環(huán)都會(huì)new出一個(gè)StringBuilder對(duì)象,然后進(jìn)行append操作,最后通過(guò)toString方法返回String對(duì)象,造成內(nèi)存資源浪費(fèi)。反例:Stringstr="start";for(inti=0;i<100;i++){str=str+"hello";}22.【推薦】final可以聲明類、成員變量、方法、以及本地變量,下列情況使用final關(guān)鍵字:1)不允許被繼承的類,如:String類。2)不允許修改引用的域?qū)ο蟆?)不允許被覆寫的方法,如:POJOsetter方法。4)不允許運(yùn)行過(guò)程中重新賦值的局部變量。5)避免上下文重復(fù)使用一個(gè)變量,使用final可以強(qiáng)制重新定義一個(gè)變量,方便更好地進(jìn)行重構(gòu)。23.【推薦】慎用Object的clone方法來(lái)拷貝對(duì)象。說(shuō)明:對(duì)象clone方法默認(rèn)是淺拷貝,若想實(shí)現(xiàn)深拷貝需覆寫clone方法實(shí)現(xiàn)域?qū)ο蟮纳疃缺闅v式拷貝。24.【推薦】類成員與方法訪問(wèn)控制從嚴(yán):1)如果不允許外部直接通過(guò)new來(lái)創(chuàng)建對(duì)象,那么構(gòu)造方法必須是private。2)工具類不允許有public或default構(gòu)造方法。3)類非static成員變量并且與子類共享,必須是protected。4)類非static成員變量并且僅在本類使用,必須是private。5)類static成員變量如果僅在本類使用,必須是private。6)若是static成員變量,考慮是否為final。7)類成員方法只供類內(nèi)部調(diào)用,必須是private。8)類成員方法只對(duì)繼承類公開,那么限制為protected。說(shuō)明:任何類、方法、參數(shù)、變量,嚴(yán)控訪問(wèn)范圍。過(guò)于寬泛的訪問(wèn)范圍,不利于模塊解耦。思考:如果是一個(gè)private的方法,想刪除就刪除,可是一個(gè)public的service成員方法或成員變量,刪除一下,不得手心冒點(diǎn)汗嗎?變量像自己的小孩,盡量在自己的視線內(nèi),變量作用域太大,無(wú)限制的到處跑,那么你會(huì)擔(dān)心的。(五) 集合處理1.【強(qiáng)制】關(guān)于hashCode和equals的處理,遵循如下規(guī)則:1)只要覆寫equals,就必須覆寫hashCode。2)因?yàn)镾et存儲(chǔ)的是不重復(fù)的對(duì)象,依據(jù)hashCode和equals進(jìn)行判斷,所以存儲(chǔ)的對(duì)象必須覆寫這兩個(gè)方法。3)如果自定義對(duì)象作為Map的鍵,那么必須覆寫hashCode和equals。說(shuō)明:String已覆寫hashCode和equals方法,所以我們可以愉快地使用String對(duì)象作為key來(lái)使用。2.【強(qiáng)制】ArrayList的subList結(jié)果不可強(qiáng)轉(zhuǎn)成ArrayList,否則會(huì)拋出ClassCastException異常,即java.util.RandomAccessSubListcannotbecasttojava.util.ArrayList。說(shuō)明:subList返回的是ArrayList的內(nèi)部類SubList,并不是ArrayList而是ArrayList的一個(gè)視圖,對(duì)于SubList子列表的所有操作最終會(huì)反映到原列表上。3.【強(qiáng)制】使用Map的方法keySet()/values()/entrySet()返回集合對(duì)象時(shí),不可以對(duì)其進(jìn)行添加元素操作,否則會(huì)拋出UnsupportedOperationException異常。4.【強(qiáng)制】Collections類返回的對(duì)象,如:emptyList()/singletonList()等都是immutablelist,不可對(duì)其進(jìn)行添加或者刪除元素的操作。反例:如果查詢無(wú)結(jié)果,返回Collections.emptyList()空集合對(duì)象,調(diào)用方一旦進(jìn)行了添加元素的操作,就會(huì)觸發(fā)UnsupportedOperationException異常。5.【強(qiáng)制】在subList場(chǎng)景中,高度注意對(duì)原集合元素的增加或刪除,均會(huì)導(dǎo)致子列表的遍歷、增加、刪除產(chǎn)生ConcurrentModificationException異常。6.【強(qiáng)制】使用集合轉(zhuǎn)數(shù)組的方法,必須使用集合的toArray(T[]array),傳入的是類型完全一致、長(zhǎng)度為0的空數(shù)組。反例:直接使用toArray無(wú)參方法存在問(wèn)題,此方法返回值只能是Object[]類,若強(qiáng)轉(zhuǎn)其它類型數(shù)組將出現(xiàn)ClassCastException錯(cuò)誤。正例:List<String>list=newArrayList<>(2);list.add("guan");list.add("bao");String[]array=list.toArray(newString[0]);說(shuō)明:使用toArray帶參方法,數(shù)組空間大小的length:1)等于0,動(dòng)態(tài)創(chuàng)建與size相同的數(shù)組,性能最好。2)大于0但小于size,重新創(chuàng)建大小等于size的數(shù)組,增加GC負(fù)擔(dān)。3)等于size,在高并發(fā)情況下,數(shù)組創(chuàng)建完成之后,size正在變大的情況下,負(fù)面影響與上相同。4)大于size,空間浪費(fèi),且在size處插入null值,存在NPE隱患。7.【強(qiáng)制】在使用Collection接口任何實(shí)現(xiàn)類的addAll()方法時(shí),都要對(duì)輸入的集合參數(shù)進(jìn)行NPE判斷。說(shuō)明:在ArrayList#addAll方法的第一行代碼即Object[]a=c.toArray();其中c為輸入集合參數(shù),如果為null,則直接拋出異常。8.【強(qiáng)制】使用工具類Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時(shí),不能使用其修改集合相關(guān)的方法,它的add/remove/clear方法會(huì)拋出UnsupportedOperationException異常。說(shuō)明:asList的返回對(duì)象是一個(gè)Arrays內(nèi)部類,并沒有實(shí)現(xiàn)集合的修改方法。Arrays.asList體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺(tái)的數(shù)據(jù)仍是數(shù)組。String[]str=newString[]{"yang","hao"};Listlist=Arrays.asList(str);第一種情況:list.add("yangguanbao");運(yùn)行時(shí)異常。第二種情況:str[0]="changed";也會(huì)隨之修改,反之亦然。9.【強(qiáng)制】泛型通配符<?extendsT>來(lái)接收返回的數(shù)據(jù),此寫法的泛型集合不能使用add方法,而<?superT>不能使用get方法,作為接口調(diào)用賦值時(shí)易出錯(cuò)。說(shuō)明:擴(kuò)展說(shuō)一下PECS(ProducerExtendsConsumerSuper)原則:第一、頻繁往外讀取內(nèi)容的,適合用<?extendsT>。第二、經(jīng)常往里插入的,適合用<?superT>10.【強(qiáng)制】在無(wú)泛型限制定義的集合賦值給泛型限制的集合時(shí),在使用集合元素時(shí),需要進(jìn)行instanceof判斷,避免拋出ClassCastException異常。說(shuō)明:畢竟泛型是在JDK5后才出現(xiàn),考慮到向前兼容,編譯器是允許非泛型集合與泛型集合互相賦值。反例:List<String>generics=null;ListnotGenerics=newArrayList(10);notGenerics.add(newObject());notGenerics.add(newInteger(1));generics=notGenerics;//此處拋出ClassCastException異常Stringstring=generics.get(0);11.【強(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);}}說(shuō)明:以上代碼的執(zhí)行結(jié)果肯定會(huì)出乎大家的意料,那么試一下把“1”換成“2”,會(huì)是同樣的結(jié)果嗎?12.【強(qiáng)制】在JDK7版本及以上,Comparator實(shí)現(xiàn)類要滿足如下三個(gè)條件,不然Arrays.sort,Collections.sort會(huì)拋IllegalArgumentException異常。說(shuō)明:三個(gè)條件如下1)x,y的比較結(jié)果和y,x的比較結(jié)果相反。2)x>y,y>z,則x>z。3)x=y,則x,z比較結(jié)果和比較結(jié)果相同。反例:下例中沒有處理相等的情況,交換兩個(gè)對(duì)象判斷結(jié)果并不互反,不符合第一個(gè)條件,在實(shí)際使用中可能會(huì)出現(xiàn)異常。newComparator<Student>(){@Overridepublicintcompare(Studento1,Studento2){returno1.getId()>o2.getId()?1:-1;}};13.【推薦】集合泛型定義時(shí),在JDK7及以上,使用diamond語(yǔ)法或全省略。說(shuō)明:菱形泛型,即diamond,直接使用<>來(lái)指代前邊已經(jīng)指定的類型。正例://diamond方式,即<>HashMap<String,String>userCache=newHashMap<>(16);//全省略方式ArrayList<User>users=newArrayList(10);14.【推薦】集合初始化時(shí),指定集合初始值大小。說(shuō)明:HashMap使用HashMap(intinitialCapacity)初始化。正例:initialCapacity=(需要存儲(chǔ)的元素個(gè)數(shù)/負(fù)載因子)+1。注意負(fù)載因子(即loaderfactor)默認(rèn)為0.75,如果暫時(shí)無(wú)法確定初始值大小,請(qǐng)?jiān)O(shè)置為16(即默認(rèn)值)。反例:HashMap需要放置1024個(gè)元素,由于沒有設(shè)置容量初始大小,隨著元素不斷增加,容量7次被迫擴(kuò)大,resize需要重建hash表,嚴(yán)重影響性能。15.【推薦】使用entrySet遍歷類集合KV,而不是keySet方式進(jìn)行遍歷。說(shuō)明:keySet其實(shí)是遍歷了2次,一次是轉(zhuǎn)為Iterator對(duì)象,另一次是從hashMap中取出key所對(duì)應(yīng)的value。而entrySet只是遍歷了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。正例:values()返回的是V值集合,是一個(gè)list集合對(duì)象;keySet()返回的是K值集合,是一個(gè)集合對(duì)象;entrySet()返回的是K-V值組合集合。16.【推薦】高度注意Map類集合K/V能不能存儲(chǔ)null值的情況,如下表格:集合類KeyValueSuper說(shuō)明Hashtable不允許為null不允許為nullDictionary線程安全ConcurrentHashMap不允許為null不允許為nullAbstractMap鎖分段技術(shù)(JDK8:CAS)TreeMap不允許為null允許為nullAbstractMap線程不安全HashMap允許為null允許為nullAbstractMap線程不安全反例:由于HashMap的干擾,很多人認(rèn)為ConcurrentHashMap是可以置入null值,而事實(shí)上,存儲(chǔ)null值時(shí)會(huì)拋出NPE異常。17.【參考】合理利用好集合的有序性(sort)和穩(wěn)定性(order),避免集合的無(wú)序性(unsort)和不穩(wěn)定性(unorder)帶來(lái)的負(fù)面影響。說(shuō)明:有序性是指遍歷的結(jié)果是按某種比較規(guī)則依次排列的。穩(wěn)定性指集合每次遍歷的元素次序是一定的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。18.【參考】利用Set元素唯一的特性,可以快速對(duì)一個(gè)集合進(jìn)行去重操作,避免使用List的contains方法進(jìn)行遍歷、對(duì)比、去重操作。(六) 并發(fā)處理1.【強(qiáng)制】獲取單例對(duì)象需要保證線程安全,其中的方法也要保證線程安全。說(shuō)明:資源驅(qū)動(dòng)類、工具類、單例工廠類都需要注意。2.【強(qiáng)制】創(chuàng)建線程或線程池時(shí)請(qǐng)指定有意義的線程名稱,方便出錯(cuò)時(shí)回溯。正例:自定義線程工廠,并且根據(jù)外部特征進(jìn)行分組,比如機(jī)房信息。publicclassUserThreadFactoryimplementsThreadFactory{privatefinalStringnamePrefix;privatefinalAtomicIntegernextId=newAtomicInteger(1);//定義線程組名稱,在jstack問(wèn)題排查時(shí),非常有幫助UserThreadFactory(StringwhatFeaturOfGroup){namePrefix="FromUserThreadFactory's"+whatFeaturOfGroup+"-Worker-";}@OverridepublicThreadnewThread(Runnabletask){Stringname=namePrefix+nextId.getAndIncrement();Threadthread=newThread(null,task,name,0,false);System.out.println(thread.getName());returnthread;}}3.【強(qiáng)制】線程資源必須通過(guò)線程池提供,不允許在應(yīng)用中自行顯式創(chuàng)建線程。說(shuō)明:線程池的好處是減少在創(chuàng)建和銷毀線程上所消耗的時(shí)間以及系統(tǒng)資源的開銷,解決資源不足的問(wèn)題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者“過(guò)度切換”的問(wèn)題。4.【強(qiáng)制】線程池不允許使用Executors去創(chuàng)建,而是通過(guò)ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。說(shuō)明:Executors返回的線程池對(duì)象的弊端如下:1)FixedThreadPool和SingleThreadPool:允許的請(qǐng)求隊(duì)列長(zhǎng)度為Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致OOM。2)CachedThreadPool:允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致OOM。5.【強(qiáng)制】SimpleDateFormat是線程不安全的類,一般不要定義為static變量,如果定義為static,必須加鎖,或者使用DateUtils工具類。正例:注意線程安全,使用DateUtils。亦推薦如下處理:privatestaticfinalThreadLocal<DateFormat>df=newThreadLocal<DateFormat>(){@OverrideprotectedDateFormatinitialValue(){returnnewSimpleDateFormat("yyyy-MM-dd");}};說(shuō)明:如果是JDK8的應(yīng)用,可以使用InstantDate,LocalDateTimeCalendar,DateTimeFormatter代替SimpleDateFormat,官方給出的解釋:simplebeautifulstrongimmutablethread-safe。6.【強(qiáng)制】必須回收自定義的ThreadLocal變量,尤其在線程池場(chǎng)景下,線程經(jīng)常會(huì)被復(fù)用,如果不清理自定義的ThreadLocal變量,可能會(huì)影響后續(xù)業(yè)務(wù)邏輯和造成內(nèi)存泄露等問(wèn)題。盡量在代理中使用try-finally塊進(jìn)行回收。正例:try{//...}finally{objectThreadLocal.remove();}7.【強(qiáng)制】高并發(fā)時(shí),同步調(diào)用應(yīng)該去考量鎖的性能損耗。能用無(wú)鎖數(shù)據(jù)結(jié)構(gòu),就不要用鎖;能鎖區(qū)塊,就不要鎖整個(gè)方法體;能用對(duì)象鎖,就不要用類鎖。說(shuō)明:盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調(diào)用RPC方法。8.【強(qiáng)制】對(duì)多個(gè)資源、數(shù)據(jù)庫(kù)表、對(duì)象同時(shí)加鎖時(shí),需要保持一致的加鎖順序,否則可能會(huì)造成死鎖。說(shuō)明:線程一需要對(duì)表A、B、C依次全部加鎖后才可以進(jìn)行更新操作,那么線程二的加鎖順序也必須是A、B、C,否則可能出現(xiàn)死鎖。9.【強(qiáng)制】在使用阻塞等待獲取鎖的方式中,必須在try代碼塊之外,并且在加鎖方法與try代碼塊之間沒有任何可能拋出異常的方法調(diào)用,避免加鎖成功后,在finally中無(wú)法解鎖。說(shuō)明一:如果在lock方法與try代碼塊之間的方法調(diào)用拋出異常,那么無(wú)法解鎖,造成其它線程無(wú)法成功獲取鎖。說(shuō)明二:如果lock方法在try代碼塊之內(nèi),可能由于其它方法拋出異常,導(dǎo)致在finally代碼塊中,unlock對(duì)未加鎖的對(duì)象解鎖,它會(huì)調(diào)用AQS的tryRelease方法(取決于具體實(shí)現(xiàn)類),拋出IllegalMonitorStateException異常。說(shuō)明三:在Lock對(duì)象的lock方法實(shí)現(xiàn)中可能拋出unchecked異常,產(chǎn)生的后果與說(shuō)明二相同。正例:Locklock=newXxxLock();//...lock.lock();try{doOthers();}finally{lock.unlock();反例:}Locklock=newXxxLock();//...try{//如果此處拋出異常,則直接執(zhí)行finally代碼塊doSomething();//無(wú)論加鎖是否成功,finally代碼塊都會(huì)執(zhí)行l(wèi)ock.lock();}finally{lock.unlock();}10.【強(qiáng)制】在使用嘗試機(jī)制來(lái)獲取鎖的方式中,進(jìn)入業(yè)務(wù)代碼塊之前,必須先判斷當(dāng)前線程是否持有鎖。鎖的釋放規(guī)則與鎖的阻塞等待方式相同。說(shuō)明:Lock對(duì)象的unlock方法在執(zhí)行時(shí),它會(huì)調(diào)用AQS的tryRelease方法(取決于具體實(shí)現(xiàn)類),如果當(dāng)前線程不持有鎖,則拋出IllegalMonitorStateException異常。正例:Locklock=newXxxLock();//...booleanisLocked=lock.tryLock();if(isLocked){try{doSomething();doOthers();}finally{lock.unlock();}}11.【強(qiáng)制】并發(fā)修改同一記錄時(shí),避免更新丟失,需要加鎖。要么在應(yīng)用層加鎖,要么在緩存加鎖,要么在數(shù)據(jù)庫(kù)層使用樂(lè)觀鎖,使用version作為更新依據(jù)。說(shuō)明:如果每次訪問(wèn)沖突概率小于20%,推薦使用樂(lè)觀鎖,否則使用悲觀鎖。樂(lè)觀鎖的重試次數(shù)不得小于3次。12.【強(qiáng)制】多線程并行處理定時(shí)任務(wù)時(shí),Timer運(yùn)行多個(gè)TimeTask時(shí),只要其中之一沒有捕獲拋出的異常,其它任務(wù)便會(huì)自動(dòng)終止運(yùn)行,如果在處理定時(shí)任務(wù)時(shí)使用ScheduledExecutorService則沒有這個(gè)問(wèn)題。13.【推薦】資金相關(guān)的金融敏感信息,使用悲觀鎖策略。說(shuō)明:樂(lè)觀鎖在獲得鎖的同時(shí)已經(jīng)完成了更新操作,校驗(yàn)邏輯容易出現(xiàn)漏洞,另外,樂(lè)觀鎖對(duì)沖突的解決策略有較復(fù)雜的要求,處理不當(dāng)容易造成系統(tǒng)壓力或數(shù)據(jù)異常,所以資金相關(guān)的金融敏感信息不建議使用樂(lè)觀鎖更新。14.【推薦】使用CountDownLatch進(jìn)行異步轉(zhuǎn)同步操作,每個(gè)線程退出前必須調(diào)用countDown方法,線程執(zhí)行代碼注意catch異常,確保countDown方法被執(zhí)行到,避免主線程無(wú)法執(zhí)行至await方法,直到超時(shí)才返回結(jié)果。說(shuō)明:注意,子線程拋出異常堆棧,不能在主線程try-catch到。15.【推薦】避免Random實(shí)例被多線程使用,雖然共享該實(shí)例是線程安全的,但會(huì)因競(jìng)爭(zhēng)同一seed導(dǎo)致的性能下降。說(shuō)明:Random實(shí)例包括java.util.Random的實(shí)例或者M(jìn)ath.random()的方式。正例:在JDK7之后,可以直接使用APIThreadLocalRandom,而在JDK7之前,需要編碼保證每個(gè)線程持有一個(gè)實(shí)例。16.【推薦】在并發(fā)場(chǎng)景下,通過(guò)雙重檢查鎖(double-checkedlocking)實(shí)現(xiàn)延遲初始化的優(yōu)化問(wèn)題隱患(可參考The"Double-CheckedLockingBroken"Declaration),推薦解決方案中較為簡(jiǎn)單一種(適用于JDK5及以上版本),將目標(biāo)屬性聲明為volatile型。反例:publicclassLazyInitDemo{privateHelperhelper=null;publicHelpergetHelper(){if(helper==null)synchronized(this){if(helper==null)helper=newHelper();}returnhelper;}//othermethodsandfields...}17.【參考】volatile解決多線程內(nèi)存不可見問(wèn)題。對(duì)于一寫多讀,是可以解決變量同步問(wèn)題,但是如果多寫,同樣無(wú)法解決線程安全問(wèn)題。說(shuō)明:如果是count++操作,使用如下類實(shí)現(xiàn):AtomicIntegercount=newAtomicInteger();count.addAndGet(1);如果是JDK8,推薦使用LongAdder對(duì)象,比AtomicLong性能更好(減少樂(lè)觀鎖的重試次數(shù))。18.【參考】HashMap在容量不夠進(jìn)行resize時(shí)由于高并發(fā)可能出現(xiàn)死鏈,導(dǎo)致CPU飆升,在開發(fā)過(guò)程中可以使用其它數(shù)據(jù)結(jié)構(gòu)或加鎖來(lái)規(guī)避此風(fēng)險(xiǎn)。19.【參考】ThreadLocal對(duì)象使用static修飾,ThreadLocal無(wú)法解決共享對(duì)象的更新問(wèn)題。說(shuō)明:這個(gè)變量是針對(duì)一個(gè)線程內(nèi)所有操作共享的,所以設(shè)置為靜態(tài)變量,所有此類實(shí)例共享此靜態(tài)變量,也就是說(shuō)在類第一次被使用時(shí)裝載,只分配一塊存儲(chǔ)空間,所有此類的對(duì)象(只要是這個(gè)線程內(nèi)定義的)都可以操控這個(gè)變量。(七) 控制語(yǔ)句1.【強(qiáng)制】在一個(gè)switch塊內(nèi),每個(gè)case要么通過(guò)continue/break/return等來(lái)終止,要么注釋說(shuō)明程序?qū)⒗^續(xù)執(zhí)行到哪一個(gè)case為止;在一個(gè)switch塊內(nèi),都必須包含一個(gè)default語(yǔ)句并且放在最后,即使它什么代碼也沒有。說(shuō)明:注意break是退出switch語(yǔ)句塊,而return是退出方法體。2.【強(qiáng)制】當(dāng)switch括號(hào)內(nèi)的變量類型為String并且此變量為外部參數(shù)時(shí),必須先進(jìn)行null判斷。反例:猜猜下面的代碼輸出是什么?publicclassSwitchString{publicstaticvoidmain(String[]args){method(null);}publicstaticvoidmethod(Stringparam){switch(param){//肯定不是進(jìn)入這里case"sth":System.out.println("it'ssth");break;//也不是進(jìn)入這里case"null":System.out.println("it'snull");break;//也不是進(jìn)入這里default:System.out.println("default");}}3.【強(qiáng)制】在if/else/for/while/do語(yǔ)句中必須使用大括號(hào)。說(shuō)明:即使只有一行代碼,避免采用單行的編碼方式:if(condition)statements;4.【強(qiáng)制】在高并發(fā)場(chǎng)景中,避免使用”等于”判斷作為中斷或退出的條件。說(shuō)明:如果并發(fā)控制沒有處理好,容易產(chǎn)生等值判斷被“擊穿”的情況,使用大于或小于的區(qū)間判斷條件來(lái)代替。反例:判斷剩余獎(jiǎng)品數(shù)量等于0時(shí),終止發(fā)放獎(jiǎng)品,但因?yàn)椴l(fā)處理錯(cuò)誤導(dǎo)致獎(jiǎng)品數(shù)量瞬間變成了負(fù)數(shù),這樣的話,活動(dòng)無(wú)法終止。5.【推薦】表達(dá)異常的分支時(shí),少用if-else方式,這種方式可以改寫成:if(condition){...returnobj;}//接著寫else的業(yè)務(wù)邏輯代碼;說(shuō)明:如果非使用if()...elseif()...else...方式表達(dá)邏輯,避免后續(xù)代碼維護(hù)困難,【強(qiáng)制】請(qǐng)勿超過(guò)3層。正例:超過(guò)3層的if-else的邏輯判斷代碼可以使用衛(wèi)語(yǔ)句、策略模式、狀態(tài)模式等來(lái)實(shí)現(xiàn),其中衛(wèi)語(yǔ)句即代碼邏輯先考慮失敗、異常、中斷、退出等直接返回的情況,以方法多個(gè)出口的方式,解決代碼中判斷分支嵌套的問(wèn)題,這是逆向思維的體現(xiàn)。示例如下:publicvoidfindBoyfriend(Manman){if(man.isUgly()){System.out.println("本姑娘是外貌協(xié)會(huì)的資深會(huì)員");return;}if(man.isPoor()){System.out.println("貧賤夫妻百事哀");return;}if(man.isBadTemper()){System.out.println("銀河有多遠(yuǎn),你就給我滾多遠(yuǎn)");return;}System.out.println("可以先交往一段時(shí)間看看");}6.【推薦】除常用方法(如getXxx/isXxx)等外,不要在條件判斷中執(zhí)行其它復(fù)雜的語(yǔ)句,將復(fù)雜邏輯判斷的結(jié)果賦值給一個(gè)有意義的布爾變量名,以提高可讀性。說(shuō)明:很多if語(yǔ)句內(nèi)的邏輯表達(dá)式相當(dāng)復(fù)雜,與、或、取反混合運(yùn)算,甚至各種方法縱深調(diào)用,理解成本非常高。如果賦值一個(gè)非常好理解的布爾變量名字,則是件令人爽心悅目的事情。正例://偽代碼如下finalbooleanexisted=(file.open(fileName,"w")!=null)&&(...)||(...);if(existed){...}反例:publicfinalvoidacquire(longarg){if(!tryAcquire(arg)&&acquireQueued(addWaiter(Node.EXCLUSIVE),arg)){selfInterrupt();}}7.【推薦】不要在其它表達(dá)式(尤其是條件表達(dá)式)中,插入賦值語(yǔ)句。說(shuō)明:賦值點(diǎn)類似于人體的穴位,對(duì)于代碼的理解至關(guān)重要,所以賦值語(yǔ)句需要清晰地單獨(dú)成為一行。反例:publicLockgetLock(booleanfair){//算術(shù)表達(dá)式中出現(xiàn)賦值操作,容易忽略count值已經(jīng)被改變threshold=(count=Integer.MAX_VALUE)-1;//條件表達(dá)式中出現(xiàn)賦值操作,容易誤認(rèn)為是sync==fairreturn(sync=fair)?newFairSync():newNonfairSync();}8.【推薦】循環(huán)體中的語(yǔ)句要考量性能,以下操作盡量移至循環(huán)體外處理,如定義對(duì)象、變量、獲取數(shù)據(jù)庫(kù)連接,進(jìn)行不必要的try-catch操作(這個(gè)try-catch是否可以移至循環(huán)體外)。9.【推薦】避免采用取反邏輯運(yùn)算符。說(shuō)明:取反邏輯不利于快速理解,并且取反邏輯寫法必然存在對(duì)應(yīng)的正向邏輯寫法。正例:使用if(x<628)來(lái)表達(dá)x小于628。反例:使用if(!(x>=628))來(lái)表達(dá)x小于628。10.【推薦】接口入?yún)⒈Wo(hù),這種場(chǎng)景常見的是用作批量操作的接口。11.【參考】下列情形,需要進(jìn)行參數(shù)校驗(yàn):1)調(diào)用頻次低的方法。2)執(zhí)行時(shí)間開銷很大的方法。此情形中,參數(shù)校驗(yàn)時(shí)間幾乎可以忽略不計(jì),但如果因?yàn)閰?shù)錯(cuò)誤導(dǎo)致中間執(zhí)行回退,或者錯(cuò)誤,那得不償失。3)需要極高穩(wěn)定性和可用性的方法。4)對(duì)外提供的開放接口,不管是RPC/API/HTTP接口。5)敏感權(quán)限入口。12.【參考】下列情形,不需要進(jìn)行參數(shù)校驗(yàn):1)極有可能被循環(huán)調(diào)用的方法。但在方法說(shuō)明里必須注明外部參數(shù)檢查要求。2)底層調(diào)用頻度比較高的方法。畢竟是像純凈水過(guò)濾的最后一道,參數(shù)錯(cuò)誤不太可能到底層才會(huì)暴露問(wèn)題。一般DAOService層都在同一個(gè)應(yīng)用中,部署在同一臺(tái)服務(wù)器中,所以DAO的參數(shù)校驗(yàn),可以省略。3)被聲明成private只會(huì)被自己代碼所調(diào)用的方法,如果能夠確定調(diào)用方法的代碼傳入?yún)?shù)已經(jīng)做過(guò)檢查或者肯定不會(huì)有問(wèn)題,此時(shí)可以不校驗(yàn)參數(shù)。(八) 注釋規(guī)約1.【強(qiáng)制】類、類屬性、類方法的注釋必須使用Javadoc規(guī)范,使用/**內(nèi)容*/格式,不得使用//xxx方式。說(shuō)明:在IDE編輯窗口中,Javadoc方式會(huì)提示相關(guān)注釋,生成Javadoc可以正確輸出相應(yīng)注釋;在IDE中,工程調(diào)用方法時(shí),不進(jìn)入方法即可懸浮提示方法、參數(shù)、返回值的意義,提高閱讀效率。2.【強(qiáng)制】所有的抽象方法(包括接口中的方法)必須要用Javadoc注釋、除了返回值、參數(shù)、異常說(shuō)明外,還必須指出該方法做什么事情,實(shí)現(xiàn)什么功能。說(shuō)明:對(duì)子類的實(shí)現(xiàn)要求,或者調(diào)用注意事項(xiàng),請(qǐng)一并說(shuō)明。3.【強(qiáng)制】所有的類都必須添加創(chuàng)建者和創(chuàng)建日期。4.【強(qiáng)制】方法內(nèi)部單行注釋,在被注釋語(yǔ)句上方另起一行,使用//注釋。方法內(nèi)部多行注釋使用/**/注釋,注意與代碼對(duì)齊。5.【強(qiáng)制】所有的枚舉類型字段必須要有注釋,說(shuō)明每個(gè)數(shù)據(jù)項(xiàng)的用途。6.【推薦】與其“半吊子”英文來(lái)注釋,不如用中文注釋把問(wèn)題說(shuō)清楚。專有名詞與關(guān)鍵字保持英文原文即可。反例:“TCP連接超時(shí)”解釋成“傳輸控制協(xié)議連接超時(shí)”,理解反而費(fèi)腦筋。7.【推薦】代碼修改的同時(shí),注釋也要進(jìn)行相應(yīng)的修改,尤其是參數(shù)、返回值、異常、核心邏輯等的修改。說(shuō)明:代碼與注釋更新不同步,就像路網(wǎng)與導(dǎo)航軟件更新不同步一樣,如果導(dǎo)航軟件嚴(yán)重滯后,就失去了導(dǎo)航的意義。8.【參考】謹(jǐn)慎注釋掉代碼。在上方詳細(xì)說(shuō)明,而不是簡(jiǎn)單地注釋掉。如果無(wú)用,則刪除。說(shuō)明:代碼被注釋掉有兩種可能性:1)后續(xù)會(huì)恢復(fù)此段代碼邏輯。2)永久不用。前者如果沒有備注信息,難以知曉注釋動(dòng)機(jī)。后者建議直接刪掉(代碼倉(cāng)庫(kù)已然保存了歷史代碼)。9.【參考】對(duì)于注釋的要求:第一、能夠準(zhǔn)確反映設(shè)計(jì)思想和代碼邏輯;第二、能夠描述業(yè)務(wù)含義,使別的程序員能夠迅速了解到代碼背后的信息。完全沒有注釋的大段代碼對(duì)于閱讀者形同天書,注釋是給自己看的,即使隔很長(zhǎng)時(shí)間,也能清晰理解當(dāng)時(shí)的思路;注釋也是給繼任者看的,使其能夠快速接替自己的工作。10.【參考】好的命名、代碼結(jié)構(gòu)是自解釋的,注釋力求精簡(jiǎn)準(zhǔn)確、表達(dá)到位。避免出現(xiàn)注釋的一個(gè)極端:過(guò)多過(guò)濫的注釋,代碼的邏輯一旦修改,修改注釋是相當(dāng)大的負(fù)擔(dān)。反例://putelephantintofridgeput(elephant,fridge);方法名put,加上兩個(gè)有意義的變量名elephant和fridge,已經(jīng)說(shuō)明了這是在干什么,語(yǔ)義清晰的代碼不需要額外的注釋。11.【參考】特殊注釋標(biāo)記,請(qǐng)注明標(biāo)記人與標(biāo)記時(shí)間。注意及時(shí)處理這些標(biāo)記,通過(guò)標(biāo)記掃描,經(jīng)常清理此類標(biāo)記。線上故障有時(shí)候就是來(lái)源于這些標(biāo)記處的代碼。1)待辦事宜(TODO):(標(biāo)記人,標(biāo)記時(shí)間,[預(yù)計(jì)處理時(shí)間])表示需要實(shí)現(xiàn),但目前還未實(shí)現(xiàn)的功能。這實(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í)糾正的情況。(九) 其它1.【強(qiáng)制】在使用正則表達(dá)式時(shí),利用好其預(yù)編譯功能,可以有效加快正則匹配速度。說(shuō)明:不要在方法體內(nèi)定義:Patternpattern=Ppile(“規(guī)則”);2.【強(qiáng)制】velocity調(diào)用POJO類的屬性時(shí),直接使用屬性名取值即可,模板引擎會(huì)自動(dòng)按規(guī)范調(diào)用POJO的getXxx(),如果是boolean基本數(shù)據(jù)類型變量(boolean命名不需要加is前綴),會(huì)自動(dòng)調(diào)用isXxx()方法。說(shuō)明:注意如果是Boolean包裝類對(duì)象,優(yōu)先調(diào)用getXxx()的方法。3.【強(qiáng)制】后臺(tái)輸送給頁(yè)面的變量必須加$!{var}——中間的感嘆號(hào)。說(shuō)明:如果var等于null或者不存在,那么${var}會(huì)直接顯示在頁(yè)面上。4.【強(qiáng)制】注意Math.random()這個(gè)方法返回是double類型,注意取值的范圍0≤x<1(能夠取到零值,注意除零異常),如果想獲取整數(shù)類型的隨機(jī)數(shù),不要將x放大10的若干倍然后取整,直接使用Random對(duì)象的nextInt或者nextLong方法。5.【強(qiáng)制】獲取當(dāng)前毫秒數(shù)System.currentTimeMillis();而不是newDate().getTime();說(shuō)明:如果想獲取更加精確的納秒級(jí)時(shí)間值,使用System.nanoTime()的方式。在JDK8中,針對(duì)統(tǒng)計(jì)時(shí)間等場(chǎng)景,推薦使用Instant類。6.【強(qiáng)制】日期格式化時(shí),傳入pattern中表示年份統(tǒng)一使用小寫的y。說(shuō)明:日期格式化時(shí),yyyy表示當(dāng)天所在的年,而大寫的YYYY代表是weekinwhichyear(JDK7之后引入的概念),意思是當(dāng)天所在的周屬于的年份,一周從周日開始,周六結(jié)束,只要本周跨年,返回的YYYY就是下一年。另外需要注意:? 表示月份是大寫的M? 表示分鐘則是小寫的m? 24小時(shí)制的是大寫的H? 12小時(shí)制的則是小寫的h正例:表示日期和時(shí)間的格式如下所示:newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");7.【推薦】不要在視圖模板中加入任何復(fù)雜的邏輯。說(shuō)明:根據(jù)MVC理論,視圖的職責(zé)是展示,不要搶模型和控制器的活。8.【推薦】任何數(shù)據(jù)結(jié)構(gòu)的構(gòu)造或初始化,都應(yīng)指定大小,避免數(shù)據(jù)結(jié)構(gòu)無(wú)限增長(zhǎng)吃光內(nèi)存。9.【推薦】及時(shí)清理不再使用的代碼段或配置信息。說(shuō)明:對(duì)于垃圾代碼或過(guò)時(shí)配置,堅(jiān)決清理干凈,避免程序過(guò)度臃腫,代碼冗余。正例:對(duì)于暫時(shí)被注釋掉,后續(xù)可能恢復(fù)使用的代碼片斷,在注釋代碼上方,統(tǒng)一規(guī)定使用三個(gè)斜杠(///)來(lái)說(shuō)明注釋掉代碼的理由。二、異常日志(一) 異常處理1.【強(qiáng)制】Java類庫(kù)中定義的可以通過(guò)預(yù)檢查方式規(guī)避的RuntimeException異常不應(yīng)該通過(guò)catch的方式來(lái)處理,比如:NullPointerException,IndexOutOfBoundsException等等。說(shuō)明:無(wú)法通過(guò)預(yù)檢查的異常除外,比如,在解析字符串形式的數(shù)字時(shí),可能存在數(shù)字格式錯(cuò)誤,不得不通過(guò)catchNumberFormatException來(lái)實(shí)現(xiàn)。正例:if(obj!=null){...}反例:try{obj.method();}catch(NullPointerExceptione){…}2.【強(qiáng)制】異常不要用來(lái)做流程控制,條件控制。說(shuō)明:異常設(shè)計(jì)的初衷是解決程序運(yùn)行中的各種意外情況,且異常的處理效率比條件判斷方式要低很多。3.【強(qiáng)制】catch時(shí)請(qǐng)分清穩(wěn)定代碼和非穩(wěn)定代碼,穩(wěn)定代碼指的是無(wú)論如何不會(huì)出錯(cuò)的代碼。對(duì)于非穩(wěn)定代碼的catch盡可能進(jìn)行區(qū)分異常類型,再做對(duì)應(yīng)的異常處理。說(shuō)明:對(duì)大段代碼進(jìn)行try-catch,使程序無(wú)法根據(jù)不同的異常做出正確的應(yīng)激反應(yīng),也不利于定位問(wèn)題,這是一種不負(fù)責(zé)任的表現(xiàn)。正例:用戶注冊(cè)的場(chǎng)景中,如果用戶輸入非法字符,或用戶名稱已存在,或用戶輸入密碼過(guò)于簡(jiǎn)單,在程序上作出分門別類的判斷,并提示給用戶。4.【強(qiáng)制】捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請(qǐng)將該異常拋給它的調(diào)用者。最外層的業(yè)務(wù)使用者,必須處理異常,將其轉(zhuǎn)化為用戶可以理解的內(nèi)容。5.【強(qiáng)制】有try塊放到了事務(wù)代碼中,catch異常后,如果需要回滾事務(wù),一定要注意手動(dòng)回滾事務(wù)。6.【強(qiáng)制】finally塊必須對(duì)資源對(duì)象、流對(duì)象進(jìn)行關(guān)閉,有異常也要做try-catch。說(shuō)明:如果JDK7及以上,可以使用try-with-resources方式?!緩?qiáng)制】不要在finally塊中使用return。說(shuō)明:try塊中的return語(yǔ)句執(zhí)行成功后,并不馬上返回,而是繼續(xù)執(zhí)行finally塊中的語(yǔ)句,如果此處存在return語(yǔ)句,則在此直接返回,無(wú)情丟棄掉try塊中的返回點(diǎn)。反例:privateintx=0;publicintcheckReturn(){try{//x等于1,此處不返回return++x;}finally{//返回的結(jié)果是2return++x;}}8.【強(qiáng)制】捕獲異常與拋異常,必須是完全匹配,或者捕獲異常是拋異常的父類。說(shuō)明:如果預(yù)期對(duì)方拋的是繡球,實(shí)際接到的是鉛球,就會(huì)產(chǎn)生意外情況。9.【強(qiáng)制】在調(diào)用RPC、二方包、或動(dòng)態(tài)生成類的相關(guān)方法時(shí),捕捉異常必須使用Throwable類來(lái)進(jìn)行攔截。說(shuō)明:通過(guò)反射機(jī)制來(lái)調(diào)用方法,如果找不到方法,拋出NoSuchMethodException。什么情況會(huì)拋出NoSuchMethodError呢?二方包在類沖突時(shí),仲裁機(jī)制可能導(dǎo)致引入非預(yù)期的版本使類的方法簽名不匹配,或者在字節(jié)碼修改框架(比如:ASM)動(dòng)態(tài)創(chuàng)建或修改類時(shí),修改了相應(yīng)的方法簽名。這些情況,即使代碼編譯期是正確的,但在代碼運(yùn)行期時(shí),會(huì)拋出NoSuchMethodError。10.【推薦】方法的返回值可以為null,不強(qiáng)制返回空集合,或者空對(duì)象等,必須添加注釋充分說(shuō)明什么情況下會(huì)返回null值。說(shuō)明:本手冊(cè)明確防止NPE是調(diào)用者的責(zé)任。即使被調(diào)用方法返回空集合或者空對(duì)象,對(duì)調(diào)用者來(lái)說(shuō),也并非高枕無(wú)憂,必須考慮到遠(yuǎn)程調(diào)用失敗、序列化失敗、運(yùn)行時(shí)異常等場(chǎng)景返回null的情況。11.【推薦】防止NPE,是程序員的基本修養(yǎng),注意NPE產(chǎn)生的場(chǎng)景:1)返回類型為基本數(shù)據(jù)類型,return包裝數(shù)據(jù)類型的對(duì)象時(shí),自動(dòng)拆箱有可能產(chǎn)生NPE。反例:publicintf(){returnInteger對(duì)象},如果為null,自動(dòng)解箱拋NPE。2)數(shù)據(jù)庫(kù)的查詢結(jié)果可能為null。3)集合里的元素即使isNotEmpty,取出的數(shù)據(jù)元素也可能為null。4)遠(yuǎn)程調(diào)用返回對(duì)象時(shí),一律要求進(jìn)行空指針判斷,防止NPE。5)對(duì)于Session中獲取的數(shù)據(jù),建議進(jìn)行NPE檢查,避免空指針。6)級(jí)聯(lián)調(diào)用obj.getA().getB().getC();一連串調(diào)用,易產(chǎn)生NPE。正例:使
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 農(nóng)機(jī)售賣租賃合同范本
- 個(gè)人領(lǐng)養(yǎng)寵物合同范例
- 公建房屋維修合同范本
- 寫退貨合同范本
- 2人合伙人協(xié)議合同范例
- 農(nóng)村水井租賃合同范例
- 農(nóng)村住宅買賣租賃合同范本
- 仿古面磚采購(gòu)合同范本
- 農(nóng)村水產(chǎn)養(yǎng)殖租賃合同范例
- 養(yǎng)殖奶牛合作合同范例
- 成本合約規(guī)劃培訓(xùn)
- 山東省濟(jì)寧市2025屆高三歷史一輪復(fù)習(xí)高考仿真試卷 含答案
- 五年級(jí)數(shù)學(xué)(小數(shù)乘法)計(jì)算題專項(xiàng)練習(xí)及答案
- 交通法規(guī)教育課件
- 產(chǎn)前診斷室護(hù)理工作總結(jié)
- 6S管理知識(shí)培訓(xùn)課件
- 小學(xué)校長(zhǎng)任期五年工作目標(biāo)(2024年-2029年)
- 湖南省長(zhǎng)郡中學(xué)2023-2024學(xué)年高二下學(xué)期寒假檢測(cè)(開學(xué)考試)物理 含解析
- 了不起的狐貍爸爸-全文打印
- 03fusionsphere虛擬化場(chǎng)景概要設(shè)計(jì)模板hld
- 火災(zāi)接警處置流程圖
評(píng)論
0/150
提交評(píng)論