版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
媒體電影大數據項目編碼規(guī)范
XX科技股份有限公司編制
目錄
一、編程規(guī)約3
(一)命名風格3
(二)常量定義7
(三)代碼格式8
(四)OOP規(guī)約11
(五)集合處理17
(六)并發(fā)處理22
(七)控制語句28
(八)注釋規(guī)約32
(九)其它34
二、異常日志35
(一)異常處理35
(二)日志規(guī)約38
三、單元測試40
四、安全規(guī)約42
五、MySQL數據庫43
(一)建表規(guī)約43
(二)索引規(guī)約46
(三)SQL語句48
(四)ORM映射49
六、工程結構50
(一)應用分層50
(二)二方庫依賴51
(三)服務器53
七、設計規(guī)約54
附1:專有名詞解釋58
一、編程規(guī)約
(一)命名風格
L【強制】代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元
符號結束。
反例:_name/name/$name/name_/name$/name
2.【強制】代碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文
的方式。
說明:正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。沱意,純拼音命
名方式更要避免采用。
正例:renminbi/alibaba/taobao/youku/hangzhou等國際通用的名稱,可
視同英文。反例:DaZhePromotion[打折]/getPingfenByName()[評分]/int某
變量二3
【強制】類名使用UpperCamelCase風格,但以下情形例外:DO/BO/DTO/V0
/AO/PO/UID等。
正例:JavaServerlessPlatform/UserDO/XmlService/TcpUdpDeal/
TaPromotion
反例:javaserverlessplatform/UserDo/XMLService/TCPUDPDeal/
TAPromotion
4.【強制】方法名、參數名、成員變量、局部變量都統(tǒng)一使用lowerCamelCase風
格,必須遵從駝峰形式。
正例:localValue/getHttpMessageO/inputUserld
5.【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不
要嫌名字長。
正例:MAX_STOCK_COUNT/CACHE_EXPIRED_TIME
反例:MAX_COUNT/EXPIREDTIME
6.【強制】抽象類命名使用Abstract或Base開頭;異常類命名使用Exception
3/44
結尾;測試類命名以它要測試的類的名稱開始,以Test結尾。
7.【強制】類型與中括號緊挨相連來表示數組,
正例:定義整形數組int[]arrayDemo;
反例:在main參數中,使用Stringargs□來定義。
8.【強制】POJO類中布爾類型變量都不要加is前綴,否則部分框架解析會引起序
列化錯誤。
說明:在本文MySQL規(guī)約中的建表約定第一條,表達是與否的值采用is-xxx的命
名方式,所以,需要在<resultMap>設置從is_xxx到xxx的映射關系。
反例:定義為基本數據類型BooleanisDeleted的屬性,它的方法也是
isDeletedO,RPC框架在反向解析的時候,“誤以為”對應的屬性名稱是deleted,
導致屬性獲取不到,進而拋出異常。
9.【強制】包名統(tǒng)一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。
包名統(tǒng)一使用單數形式,但是類名如果有復數含義,類名可以使用復數形式。
正例:應用工具類包名為com.alibaba.ai.utiK類名為MessageUtils(此規(guī)則參
考spring的框架結構)
10.【強制】避免在子父類的成員變量之間、或者不同代碼塊的局擊變量之間采用
完全相同的命名,使可讀性降低。
說明:子類、父類成員變量名相同,即使是public類型的變量也是能夠通過編譯,
而局部變量在同一方法內的不同代碼塊中同名也是合法的,但是要避免使用。對于非
setter/getter的參數名稱也要避免與成員變量名稱相同。
反例:
publicclassConfusingName{publicintage;
//非setter/getter的參數名稱,不允許與本類成員變量同名
publicvoidgetData(Stringalibaba){if(condition){
finalintmoney=531;
//...
4/44
for(inti=0;i<10;i++){
//在同一方法體中,不允許與其它代碼塊中的money命名相同
finalintmoney=615;
//...
)
)
)
classSonextendsConfusingName
//不允許與父類的成員變量名稱相同
publicintage;
)
11.【強制】杜絕完全不規(guī)范的縮寫,避免望文不知義。
反例:Abstractclass"縮寫"命名成AbsClass;condition"縮寫”命名成
condi,此類隨意縮寫嚴重降低了代碼的可閱讀性。
12.【推薦】為了達到代碼自解釋的目標,任何自定義編程元素在命名時,使用盡
量完整的單詞組合來表達其意。
正例:在JDK中,表達原子更新的類名為:AtomicReferenceFieldUpdater。反例:
inta的隨意命名方式。
13.【推薦】在常量與變量的命名時,表示類型的名詞放在詞尾,以提升辨識度。
正例:startTime/workQueue/nameList/TERMINATED_THREAD_COUNT
反例:startedAt/QueueOfWork/listName/COUNT_TERMINATED_THREAD
14.【推薦】如果模塊、接口、類、方法使用了設計模式,在命名時需體現出具體
模式。
說明:將設計模式體現在名字中,有利于閱讀者快速理解架構設計理念
正例:publicclassOrderFactory;
publicclassLoginProxy;
5/44
publicclassResourceobserver;
15.【推薦】接口類中的方法和屬性不要加任何修飾符號(public乜不要加),保
持代碼的簡潔性,并加上有效的Javadoc注釋。盡量不要在接口里定義變量,如果一
定要定義變量,肯定是與接口方法相關,并且是整個應用的基礎常量。
正例:接口方法簽名voidcommit();
接口基礎常量StringCOMPANY='alibabaM;
反例:接口方法定義publicabstractvoidf();
說明:JDK8中接口允許有默認實現,那么這個default方法,是對所有實現類都
有價值的默認實現。
16.接口和實現類的命名有兩套規(guī)則:
1)【強制】對于Service和DAO類,基于SOA的理念,暴露出來的服務一定是
接口,內部的實現類用Impl的后綴與接口區(qū)別。
正例:CacheServicelmpl實現CacheService接口。
2)L薦】如果是形容能力的接口名稱,取對應的形容詞為接口名(通常是-able
的形容詞)。
正例:AbstractTranslator實現Translatable接口。
17.【參考】枚舉類名帶上Enum后綴,枚舉成員名稱需要全大寫,單詞間用下劃
線隔開。說明:枚舉其實就是特殊的類,域成員均為常量,且構造方法被默認強制是私
有。
正例:枚舉名字為ProcessStatusEnum的成員名稱:SUCCESS/UNKN0WN_REAS0No
18.【參考】各層命名規(guī)約:
Service/DAO層方法命名規(guī)約
1)獲取單個對象的方法用get做前綴。
2)獲取多個對象的方法用list做前綴,復數形式結尾如:listObjects。
3)獲取統(tǒng)計值的方法用count做前綴。
4)插入的方法用save/insert做前綴。
5)刪除的方法用remove/delete做前綴。
6)修改的方法用update做前綴。
6/44
B)領域模型命名規(guī)約
1)數據對象:xxxDO,xxx即為數據表名。
2)數據傳輸對象:xxxDTO,xxx為業(yè)務領域相關的名稱。
3)展示對象:xxxVO,xxx一般為網頁名稱。
4)POJO是DO/DTO/BO/VO的統(tǒng)稱,禁止命名成xxxPOJOo
(二)常量定義
1.【強制】不允許任何魔法值(即未經預先定義的常量)直接出現在代碼中。
反例:Stringkey="Id#taobao_"+tradeld;cache,put(key,value);
//緩存get時,由于在代碼復制時,漏掉下劃線,導致緩存擊穿而出現問題
2.【強制】在long或者Long賦值時,數值后使用大寫的L,不能是小寫的1,
小寫容易跟數字1混淆,造成誤解。
說明:Longa=21;寫的是數字的21,還是Long型的2。
3.【推薦】不要使用一個常量類維護所有常量,要按常量功能進行歸類,分開維護。
說明:大而全的常量類,雜亂無章,使用查找功能才能定位到修改的常量,不利于理解
和維護。正例:緩存相關常量放在類CacheConsts下;系統(tǒng)配置相關常量放在類
ConfigConsts下。
4.【推薦】常量的復用層次有五層:跨應用共享常量、應用內共享常量、子工程內
共享常量、包內共享常量、類內共享常量。
1)跨應用共享常量:放置在二方庫中,通常是client,jar中的constant目錄
下。
2)應用內共享常量:放置在一方庫中,通常是子模塊中的constant目錄下。反
例:易懂變量也要統(tǒng)一定義成應用內共享常量,兩位工程師在兩個類中分別定義了“YES”
的變量:
類A中:publicstaticfinalStringYES="yes";
類B中:publicstaticfinalStringYES="y";A.YES.equals(B.YES),預期
是true,但實際返回為false,導致線上問題。
3)子工程內部共享常量:即在當前子工程的constant目錄下。
4)包內共享常量:即在當前包下單獨的constant目錄下。
7/44
5)類內共享常量:直接在類內部privatestaticfinal定義。
5.【推薦】如果變量值僅在一個固定范圍內變化用enum類型來定義。說明:如
果存在名稱之外的延伸屬性應使用enum類型,下面正例中的數字就是延伸信息,表示
一年中的第幾個季節(jié)。
正例:
publicenumSeasonEnum{
SPRING(1),SUMMER(2),AUTUMN(3),WINTER(4);
privateintseq;SeasonEnum(intseq){
this.seq=seq;
)
publicintgetSeqO;returnseq;
)
)
(三)代碼格式
1.【強制】如果是大括號內為空,則簡潔地寫成{}即可,大括號中間無需換行和
空格;如果是非空代碼塊則:
1)左大括號前不換行。
2)左大括號后換行。
3)右大括號前換行。
4)右大括號后還有else等代碼則不換行;表示終止的右大括號后必須換行。
2.【強制】左小括號和字符之間不出現空格;同樣,右小括號和字符之間也不出
現空格;而左
大括號前需要空格。詳見第5條下方正例提示。
反例:if(空格a二二b空格)
3.【強制】if/for/while/switch/do等保留字與括號之間都必須加空格。
4.【強制】任何二目、三目運算符的左右兩邊都需要加一個空格。
說明:運算符包括賦值運算符二、邏輯運算符&&、加減乘除符號等。
8/44
5.【強制】采用4個空格縮進,禁止使用tab字符。
說明:如果使用tab縮進,必須設置1個tab為4個空格。IDEA設置tab為
4個空格時,請勿勾選Usetabcharacter;而在eclipse中,必須勾選insert
spacesfortabso
正例:(涉及1-5點)
publicstaticvoidmain(String[]args){
//縮進4個空格
Stringsay="hello”;
//運算符的左右必須有一個空格
intflag=0;
//關鍵詞if與括號之間必須有一個空格,括號內的f與左括號,0與右括號不
需要空格
if(flag==0){System,out.println(say);
)
//左大括號前加空格且不換行;左大括號后換行
if(flag=二1){System.out.printin("world");
//右大括號前換行,右大括號后有else,不用換行
}else{
System.out.printin("ok");
//在右大括號后直接結束,則必須換行
6.【強制】注釋的雙斜線與注釋內容之間有且僅有一個空格。
正例:
//這是示例注釋,請注意在雙斜線之后有一個空格
Stringparam=newString();
9/44
7.【強制】在進行類型強制轉換時,右括號與強制轉換值之間不需要任何空格隔
開。
正例:
longfirst=1000000000000L;intsecond=(int)first+2;
8.【強制】單行字符數限制不超過120個,超出需要換行,換行時遵循如下原貝11:
1)第二行相對第一行縮進4個空格,從第三行開始,不再繼續(xù)縮進,參考示例。
2)運算符與下文一起換行。
3)方法調用的點符號與下文一起換行。
4)方法調用中的多個參數需要換行時,在逗號后進行。
5)在括號前不要換行,見反例。
正例:
StringBuildersb=newStringBuilder(^;
//超過120個字符的情況下,換行縮進4個空格,點號和方法名稱一起換行
sb.append('*Jack0).append("Ma")
.append("alibaba")...
.append("alibaba")
.append(ualibaban);
反例:
StringBuildersb=newStringBuilder(>;
//超過120個字符的情況下,不要在括號前換行
sb.append("JackH).append("Ma")…append("alibaba");
//參數很多的方法調用可能超過120個字符,不要在逗號前換行
method(args1,args2,args3,...,argsX);
9.【強制】方法參數在定義和傳入時,多個參數逗號后邊必須加空格。
正例:下例中實參的argsl,后邊必須要有一個空格。
ir.ethod(args1,args2,args3);
10/44
10.【強制】IDE的textfileencoding設置為UTF-8;IDE中文件的換行符使
用Unix格式,不要使用Windows格式。
11.【推薦】單個方法的總行數不超過80行。說明:除注釋之外的方法簽名、左
右大括號、方法內代碼、空行、回車及任何不可見字符的總行數不超過80行。正例:
代碼邏輯分清紅花和綠葉,個性和共性,綠葉邏輯單獨出來成為額外方法,使主干代碼
更加清晰;共性邏輯抽取成為共性方法,便于復用和維護。
12.【推薦】沒有必要增加若干空格來使變量的賦值等號與上一行對應位置的等號
對齊。
正例:
intone=1;longtwo=2L;floatthree=3F;
StringBuildersb=newStringBuilder(>;
說明:增加sb這個變量,如果需要對齊,則給one.two.three都要增加幾個空
格,在變量比較多的情
況下,是非常累贅的事情。
13.【推薦】不同邏輯、不同語義、不同業(yè)務的代碼之間插入一個空行分隔開來以
提升可讀性。
說明:任何情形,沒有必要插入多個空行進行隔開。
(四)OOP規(guī)約
1.【強制】避免通過一個類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法,無謂增
加編譯器解析成本,直接用類名來訪問即可。
2.【強制】所有的覆寫方法,必須加@0verride注解。
說明:getObject()與getObject()的問題。一個是字母的0,一個是數字的0,加
?Override可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,
其實現類會馬上編譯報錯。
3.【強制】相同參數類型,相同業(yè)務含義,才可以使用Java的可變參數,避免
使用Object。
11/44
說明:可變參數必須放置在參數列表的最后。(提倡同學們盡量不用可變參數編程)
正例:publicList<User>listUsers(Stringtype,Long...ids){…}
4.【強制】外部正在調用或者二方庫依賴的接口,不允許修改方法簽名,避免對
接口調用方產生影響。接口過時必須加@Deprecated注解,并清晰地說明采用的新接口
或者新服務是什么。
5.【強制】不能使用過時的類或方法。
說明:java.net.URLDecoder中的方法decoce(StringencodeStr)這個方法已經
過時,應該使用雙參數decode(Stringsource,Stringencode)o接口提供方既然明確
是過時接口,那么有義務同時提供新的接口;作為調用方來說,有義務云考證過時方法
的新實現是什么。
6.【強制】Object的equals方法容易拋空指針異常,應使用常量或確定有值的
對象來調用equalso
正例:"test",equals(object);反例:object,equals(Mtesttt);
說明:推薦使用java.util.Objectsftequals(JDK7引入的工具類)。
7.【強制】所有整型包裝類對象之間值的比較,全部使用equals方法比較。
說明:對于Integervar=?在-128至127范圍內的賦值,Integer對象是在
TntegerCache.cache產生,會復用已有對象,這個區(qū)間內的Integer值可以直接使用
=進行判斷,但是這個區(qū)間之外的所有數據,都會在堆上產生,并不會復用已有對象,
這是一個大坑,推薦使用equals方法進行判斷。
8.【強制】浮點數之間的等值判斷,基本數據類型不能用二來比較,包裝數據類
型不能用equals來判斷。說明:浮點數采用“尾數+階碼”的編碼方式,類似于科學
計數法的“有效數字+指數”的表示方式。二進制無法精確表示大部分的一進制小數,具
體原理參考《碼出高效》。
反例:
floata=1.Of-0.9f;floatb=0.9f-0.8f;
if(a二二b)
12/44
//預期進入此代碼快,執(zhí)行其它業(yè)務邏輯
//但事實上a==b的結果為false
)
Floatx=Float.valueOf(a);Floaty=Float.valueOf(b);if(x.equals(y))
(
//預期進入此代碼快,執(zhí)行其它業(yè)務邏輯
//但事實上equals的結果為false
)
正例:
(1)指定一個誤差范圍,兩個浮點數的差值在此范圍之內,則認為是相等的。
floata=1.Of-0.9f;floatb=0.9f-0.8f;floatdiff=le-6f;
if(Math.abs(a-b)<diff)System.out.println(Htrue,F);
)
(2)使用BigDecimal來定義值,再進行浮點數的運算操作。
BigDecimala=newBigDecimal("1.0n);BigDecimalb=new
BigDecimal("0.9");BigDecimalc=newBigDecimal(,F0.8,r);
BigDecimalx-a.subtract(b);BigDecimaly二b.subtract(c);
if(x.equals(y)){System.out.println('ftrueH);
9.【強制】定義數據對象DO類時,屬性類型要與數據庫字段類型相匹配。
正例:數據庫字段的bigint必須與類屬性的Long類型相對應。
反例:某個案例的數據庫表id字段定義類型bigintunsigned,實際類對象屬性
13/44
為Integer,隨著id越來越大,超過Integer的表示范圍而溢出成為負數。
10.【強制】為了防止精度損失,禁止使用構造方法BigDecimal(double)的方式把
double值轉化為BigDecimal對象。說明:BigDecimal(double)存在精度損失風險,
在精確計算或值比較的場景中可能會導致業(yè)務邏輯異常。如:BigDecimalg=new
BigDecimal(0.If);實際的存儲值為:0.10000000149
正例:優(yōu)先推薦入參為String的構造方法,或使用BigDecimal的valueOf方法,
此方法內部其實執(zhí)行了
Double的toString,而Double的toString按double的實際能表達的精度對
尾數進行了截斷。
BigDecimalrecommendl=newBigDecimal(n0.1n);BigDecimalrecommend2
BigDecimal.valueOf(0.1);
11.關于基本數據類型與包裝數據類型的使用標準如下:
1)【強制】所有的POJO類屬性必須使用包裝數據類型。
2)【強制】RPC方法的返回值和參數必須使用包裝數據類型。
3)【推彳所有的局部變量使用基本數據類型。
說明:POJO類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,
任何NPE問題,或者入庫檢查,都由使用者來保證。
正例:數據庫的查詢結果可能是null,因為自動拆箱,用基本數據類型接收有NPE
風險°反例:比如顯示成交總額漲跌情況,即正負x%,x為基本數據類型,調用的
RPC服務,調用不成功時,返回的是默認值,頁面顯示為0%,這是不合理的,應該顯
示成中劃線。所以包裝數據類型的null值,能夠表示額外的信息,如:遠程調用失敗,
異常退出。
12.【強制】定義D0/DT0/V0等POJO類時,不要設定任何屬性默認值。
反例:POJO類的createTime默認值為newDate(),但是這個屬性在數據提取時
并沒有置入具體值,在更新其它字段時又附帶更新了此字段,導致創(chuàng)建時間被修改成當
前時間。
13.【強制】序列化類新增屬性時,請不要修改serialVersionUID字段,避免反
序列失?。蝗绻耆患嫒萆?,避免反序列化混亂,那么請修改serialVersionUID
14/44
值。
說明:注意serialVersionUlD不一致會拋出序列化運行時異常。
14.【強制】構造方法里面禁止加入任何業(yè)務邏輯,如果有初始化邏輯,請放在
init方法中。
15.【強制】POJO類必須寫toString方法。使用IDE中的工具:source>
generatetoString時,如果繼承了另一個P0J0類,注意在前面加一下
super.toStringo說明:在方法執(zhí)行拋出異常時,可以直接調用P0J0的toStringO
方法打印其屬性值,便于排查問題。
16.【強制】禁止在P0J0類中,同時存在對應屬性xxx的isXxx()和getXxxO
方法。
說明:框架在調用屬性XXX的提取方法時,并不能確定哪個方法一定是被優(yōu)先調用
到。
17.【推薦】使用索引訪問用String的split方法得到的數組時,需做最后一個
分隔符后有無內容的檢查,否則會有拋IndexOutOfBoundsException的風險。
說明:
Stringstr="a,b,c,,“;
String[]ary=str.split(,r,°);
//預期大于3,結果是3System.out.println(ary.length);
18.【推薦】當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序
放置在一起,便于閱讀,此條規(guī)則優(yōu)先于下一條。
19.[-:1#-]類內方法定義的順序依次是:公有方法或保護方法>私有方法>
getter/setter方法。說明:公有方法是類的調用者和維護者最關心的方法,首屏
展示最好;保護方法雖然只是子類關心,也可能是“模板設計模式”下的核心方法;而
私有方法外部一般不需要特別關心,是一個黑盒實現;因為承載
的信息價值較低,所有Service和DAO的getter/setter方法放在類體最后。
20.【推薦】setter方法中,參數名稱與類成員變量名稱一致,this.成員名=
參數名。在getter/setter方法中,不要增加業(yè)務邏輯,增加排查問題的難度。
15/44
反例:
publicIntegergetDataO{if(condition){
returnthis,data+100;
}else{
returnthis,data-100;
21.【推薦】循環(huán)體內,字符串的連接方式,使用StringBuilder的append方法
進行擴展。
說明:下例中,反編譯出的字節(jié)碼文件顯示每次循環(huán)都會new出一個
StringBuilder對象,然后進行
append操作,最后通過toString方法返回String對象,造成內存資源浪費。
反例:
Stringstr="start”;
for(inti=0;i<100;i++){str=str+"hell。";
)
22.【佳薦】final可以聲明類、成員變量、方法、以及本地變量,下列情況使用
final關鍵字:
1)不允許被繼承的類,如:String類。
2)不允許修改引用的域對象。
3)不允許被覆寫的方法,如:P0J0類的setter方法。
4)不允許運行過程中重新賦值的局部變量。
5)避免上下文重復使用一個變量,使用final可以強制重新定義一個變量,方
便更好地進行重構。
23.【推薦】慎用Object的clone方法來拷貝對象。
16/44
說明:對象clone方法默認是淺拷貝,若想實現深拷貝需覆寫clone方法實現域
對象的深度遍歷式拷貝。
24.【推薦】類成員與方法訪問控制從嚴:
1)如果不允許外部直接通過new來創(chuàng)建對象,那么構造方法必須是privateo
2)工具類不允許有public或default構造方法。
3)類非static成員變量并且與子類共享,必須是protectedo4)類非
static成員變量并且僅在本類使用,必須是privateo5)類static成員變量如果
僅在本類使用,必須是privateo6)若是static成員變量,考慮是否為finalo
7)類成員方法只供類內部調用,必須是private。
8)類成員方法只對繼承類公開,那么限制為protectedo說明:任何類、方法、
參數、變量,嚴控訪問范圍。過于寬泛的訪問范圍,不利于模塊解耦。思考:如果是一
個private的方法,想刪除就刪除,可是一個public的service成員方法或成員變
量,刪除一下,不
得手心冒點汗嗎?變量像自己的小孩,盡量在自己的視線內,變量作用域太大,無
限制的到處跑,那么你會擔心的。
(五)集合處理
1.【強制】關于hashCode和equals的處理,遵循如下規(guī)則:
1)只要覆寫equals,就必須覆寫hashCodeo
2)因為Set存儲的是不重復的對象,依據hashCode和equals進行判斷,所以
Set存儲的對象必須覆寫這兩個方法。
3)如果自定義對象作為Map的鍵,那么必須覆寫hashCode和equalso
說明:String已覆寫hashCode和equals方法,所以我們可以愉快地使用
String對象作為key來使用。
2.【強制】ArrayList的subList結果不可強轉成ArrayList,否則會拋出
ClassCastException異常,即java.util.RandomAccessSubListcannotbecastto
java.util.ArrayList。
說明:subList返回的是ArrayList的內部類SubList,并不是ArrayList而是
ArrayList的一個視圖,對于SubList子列表的所有操作最終會反映到原列表上。
17/44
3.【強制】使用Map的方法keySet()/values()/entrySet()返回集合對象時,不
可以對其進行添加元素操作,否則會拋出UnsupportedOperationException異常。
4.【強制】Collections類返回的對象,如:emptyList()/singletonList()等都
是immutablelist,不可對其進行添加或者刪除元素的操作。
反例:如果查詢無結果,返回Collections.emptyList()空集合對象,調用方一旦
進行了添加元素的操作,就會觸發(fā)UnsupportedOperationException異常。
5.【強制】在subList場景中,高度注意對原集合元素的增加或刪除,均會導致
子列表的遍歷、增加、刪除產生ConcurrentModificationException異常。
6.【強制】使用集合轉數組的方法,必須使用集合的toArray(T[]array),傳入
的是類型完全一致、長度為0的空數組。
反例:直接使用toArray無參方法存在問題,此方法返回值只能是Object口類,
若強轉其它類型數組將出現ClassCastException錯誤。
正例:
List<String>list=newArrayListO(2);list,add(nguann);
list.add("bao");
String1]array=list.toArray(newString[0]);
說明:使用toArray帶參方法,數組空間大小的length:
1)等于0,動態(tài)創(chuàng)建與size相同的數組,性能最好。
2)大于0但小于size,重新創(chuàng)建大小等于size的數組,增加GC負擔。
3)等于size,在高并發(fā)情況下,數組創(chuàng)建完成之后,size正在變大的情況下,
負面影響與上相同。
4)大于size,空間浪費,且在size處插入null值,存在NPE隱患。
7.【強制】在使用Collection接口任何實現類的addAll()方法時,都要對輸入
的集合參數進行NPE判斷。
說明:在ArrayList#addAl1方法的第一行代碼即Object[]a=c.toArray();其
中c為輸入集合參數,如果為null,則直接拋出異常。
18/44
8.【強制】使用工具類Arrays.asListO把數組轉換成集合時,不能使用其修改
集合相關的方法,它的add/remove/clear方法會拋出
UnsupportedOperationException異常。說明:asList的返回對象是一個Arrays內
部類,并沒有實現集合的修改方法。Arrays.asList體現的是適配器模式,只是轉換接
口,后臺的數據仍是數組。
String口str=newStringf]{"yang","hao"};Listlist=
Arrays.asList(str);
第一種情況:list,add("yangguanbao");運行時異常。第二種情況:str[0]=
"changed";也會隨之修改,反之亦然。
9.【強制】泛型通配符<?extendsT》來接收返回的數據,此寫法的泛型集合不能
使用add方法,而<?superT>不能使用get方法,作為接口調用賦值時易出錯。
說明:擴展說一下PECS(ProducerExtendsConsumerSuper)原則:第一、頻繁往
外讀取內容的,適合用<?extendsT>。第二、經常往里插入的,適合用<?superT>
10.【強制】在無泛型限制定義的集合賦值給泛型限制的集合時,在使用集合元素
時,需要進行
instanceof判斷,避免拋出ClassCastException異常。
說明:畢竟泛型是在JDK5后才出現,考慮到向前兼容,編譯器是允許非泛型集合
與泛型集合互相賦值。反例:
List<String>generics=null;
ListnotGenerics=newArrayList(10);notGenerics.add(newObject());
notGenerics.add(newInteger1));
generics=notGenerics;
//此處拋出ClassCastException異常
Stringstring=generics,get(0);
11.【強制】不要在foreach循環(huán)里進行元素的remove/add操作。remove元素
請使用
Iterator方式,如果并發(fā)操作,需要對Iterator對象加鎖。
19/44
正例:
List<String>list=newArrayListO();list.add(T);
list.add("2");
Iterator<String>iterator=list,iterator0;while(iterator.hasNext())
{
Stringitem=iterator,next();
if(刪除元素的條件){
iterator,remove();
)
)
反例:
for(Stringitem:list){
if("I,1,equals(item)){list,remove(item);
)
)
說明:以上代碼的執(zhí)行結果肯定會出乎大家的意料,那么試一下把“1”換成“2”,
會是同樣的結果嗎?
12.【強制】在JDK7版本及以上,Comparator實現類要滿足如下三個條件,不然
Arrays,sort,Collections,sort會拋IIlegalArgumcntException
說明:三個條件如下
1)x,y的比較結果和y,x的比較結果相反。
2)x>y,y>z,則x>zo
3)x=y,則x,z比較結果和y,z比較結果相同。反例:下例中沒有處理相等
的情況,交換兩個對象判斷結果并不互反,不符合第一個條件,在實際使用中
可能會出現異常。
newComparator<Student>(){
20/44
?Override
publicintcompare(Studentol,Studento2){returnol.getld()>
o2.getldO?1:-1;
13.【推薦】集合泛型定義時,在JDK7及以上,使用diamond語法或全省略。
說明:菱形泛型,即diamond,直接使用?來指代前邊已經指定的類型。正例:
//diamond方式,即<>
HashMap<String,String>userCache=newHashMapO(16);
//全省略方式
ArrayList<User>users=newArrayList(10);
14.【推薦】集合初始化時,指定集合初始值大小。
說明:HashMap使用HashMap(intinitialcapacity)初始化。
正例:initialcapacity=(需要存儲的元素個數/負載因子)+1。注意負載因子
(即loaderfactor)默認為0.75,如果暫時無法確定初始值大小,請設置為16(即
默認值)。
反例:HashMap需要放置1024個元素,由于沒有設置容量初始大小,隨著元素不
斷增加,容量7次被迫擴大,resize需要重建hash表,嚴重影響性能。
15.【推薦】使用entrySet遍歷Map類集合KV,而不是keySet方式進行遍歷。
說明:keySet其實是遍歷了2次,一次是轉為Iterator對象,另一次是從
hashMap中取出key所對應的value。而entrySet只是遍歷了一次就把key和
value都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。
正例:values。返回的是V值集合,是一個list集合對象;keySet。返回的是K
值集合,是一個Set集合
對象;entrySet()返回的是K-V值組合集合。
16.【推薦】高度注意Map類集合K/V能不能存儲null值的情況,如下表格:
21/44
集合類KeyValueSuper_說明J
Hashtable不允許不允許Dictio線程安全
ConcurrentH不允許不允許Abstra_鎖分段技術
TreeMap不允許允許為Abstra線程不安全
HashMap允許為允許為Abstra線程不安全
反例:由于HashMap的干擾,很多人認為Concurrent!lashMap是可以置入null
值,而事實上,存儲
null值時會拋出NPE異常。
17.【參考】合理利用好集合的有序性(sort)和穩(wěn)定性(order),避免集合的無序性
(unsort)和不穩(wěn)定性(unorder)帶來的負面影響。說明:有序性是指遍歷的結果是按某
種比較規(guī)則依次排列的。穩(wěn)定性指集合每次遍歷的元素次序是一定的。如:ArrayList
是order/unsort;HashMap是unorder/unsort;TreeSet是order/sorto
18.【參考】利用Set元素唯一的特性,可以快速對一個集合進行去重操作,避免
使用List的contains方法進行遍歷、對比、去重操作。
(六)并發(fā)處理
1.【強制】獲取單例對象需要保證線程安全,其中的方法也要保證線程安全。
說明:資源驅動類、工具類、單例工廠類都需要注意。
2.【強制】創(chuàng)建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。
正例:自定義線程工廠,并且根據外部特征進行分組,比如機房信息。
publicclassUserThreadFactoryimplementsThreadFactory{
privatefinalStringnamcPrefix;
privatefinalAtomiclntegernextld=newAtomiclnteger(1);
//定義線程組名稱,在jstack問題排查時,非常有幫助
LserThreadFcictory1StringwhatFeaturOfGroup(
22/44
namePrefix="FromUserThreadFactory's"+whatFeaturOfGroup+^-Worker-11;
?Override
publicThreadnewThreeid(Runnabletask){
Stringname=namePrefix+nextld.getAndncrement();Threadthread=new
Thread(null,task,name,0,false);
System.out.printin(thread.getXame());returnthread;
3.【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式創(chuàng)建線程。
說明:線程池的好處是減少在創(chuàng)建和銷毀線程上所消耗的時間以及系統(tǒng)資源的開銷,
解決資源不足的問題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導致消
耗完內存或者“過度切換”的問題。
4.【強制】線程池不允許使用Executors去創(chuàng)建,而是通過ThreadPoolExecutor
的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規(guī)則,規(guī)避資源耗盡的風險。
說明:Executors返回的線程池對象的弊端如下:
1)FixedThreadPool和SingleThreadPool:
允許的請求隊列長度為Integer.MAX.VALUE,可能會堆積大量的請求,從而導致
OOMo2)CachedThreadPool:
允許的創(chuàng)建線程數量為Integer.MAX.VALUE,可能會創(chuàng)建大量的線程,從而導致
OOMo
5.【強制】SimpleDateFormat是線程不安全的類,一般不要定義為static變
量,如果定義為
static,必須加鎖,或者使用DateUtils工具類。
正例:注意線程安全,使用DateUtilso亦推薦如下處理:
23/44
privatestaticfinalThreadLocal<DateFormat>df=new
ThreadLocal<DateFormat>(){
?Override
protectedDateFormatinitialValue(){
returnnewSimpleDateFormat(Hyyyy-MM-ddn);
)
);
說明:如果是JDK8的應用,可以使用Instant代替Date,LocalDateTime代替
Calendar,DateTimeFormatter代替SimpleDateFormat,官方給出的解釋:simple
beautifulstrongimmutablethread-safe。
6.【強制】必須回收自定義的ThreadLocal變量,尤其在線程池場景下,線程經
常會被復用,如果不清理自定義的ThreadLocal變量,可能會影響后續(xù)業(yè)務邏輯和造
成內存泄露等問題。盡量在代理中使用try-finally塊進行回收。
正例:
objectThreadLocal.set(userinfo);try{
//...
}finally{
objectThreadLocal.remove();
)
7.【強制】高并發(fā)時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,
就不要用鎖;能鎖區(qū)塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。說明:
盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調用RPC方法。
8.【強制】對多個資源、數據庫表、對象同時加鎖時,需要保持一致的加鎖順序,
否則可能會造成死鎖。
說明:線程一需要對表A、B、C依次全部加鎖后才可以進行更新操作,那么線程二
的加鎖順序也必須是A、B、C,否則可能出現死鎖。
9.【強制】在使用阻塞等待獲取鎖的方式中,必須在try代碼塊之外,并且在加
24/44
鎖方法與"y代碼塊之間沒有任何可能拋出異常的方法調用,避免加鎖成功后,在
finally中無法解鎖。說明一:如果在lock方法與try代碼塊之間的方法調用拋出
異常,那么無法解鎖,造成其它線程無法成功獲取鎖。
說明二:如果lock方法在try代碼塊之內,可能由于其它方法拋出異常,導致在
finally代碼塊中,unlock對未加鎖的對象解鎖,它會調用AQS的tryRelease方法
(取決于具體實現類),拋出11legalMonitorStateException異常。
說明三:在Lock對象的lock方法實現中可能拋出unchecked異常,產生的后果
與說明二相同。
正例:
Locklock=newXxxLockO;
//...
lock,lock();try{
doSomethingO;doOthers();
}finally{
lock,unlock();
反例:
)
Locklock=newXxxLock();
//...
try(
//如果此處拋出異常,則直接執(zhí)行finally代碼塊
doSomethingO;
//無論加鎖是否成功,finally代碼塊都會執(zhí)行
lock,lock();doOthers();
}finally{
25/44
lock,unlock();
10.【強制】在使用嘗試機制來獲取鎖的方式中,進入業(yè)務代碼塊之前,必須先判
斷當前線程是否持有鎖。鎖的釋放規(guī)則與鎖的阻塞等待方式相同。
說明:Lock對象的unlock方法在執(zhí)行時,它會調用AQS的tryRelease方法
(取決于具體實現類),如果當前線程不持有鎖,則拋出
HlegalMonitorStateException異常。
正例:
Locklock=newXxxLock();
//...
booleanis
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 養(yǎng)老院老年人意外傷害預防與處理制度
- 系統(tǒng)工程考試題目及答案
- 門前四包責任制度
- 銷售人員獎罰制度
- 碳水交易事例分析題目及答案
- 通過公司法證券法明確中小股東權利如累積投票權、關聯(lián)交易回避表決制度
- 運輸隱患排查治理制度
- 財務資料申請制度
- 該制度的程序實現主要依賴于民事訴訟法中的行為保全制度
- 藍與美獎勵制度
- 空氣能維保合同協(xié)議
- 2019營口天成消防JB-TB-TC5120 火災報警控制器(聯(lián)動型)安裝使用說明書
- 買賣肉合同樣本
- 2025年中國三氯丙酮市場調查研究報告
- 五下語文快樂讀書吧《三國演義》導讀單
- 2025屆高考語文復習:以《百合花》為例掌握小說考點
- 面向對象系統(tǒng)分析與設計(MOOC版)全套教學課件
- DLT-循環(huán)流化床鍋爐停(備)用維護保養(yǎng)導則
- JT-T-1248-2019營運貨車能效和二氧化碳排放強度等級及評定方法
- 人教PEP英語六年級下冊全冊教案教學設計及教學反思
- 語文七年級下字帖打印版
評論
0/150
提交評論