运用方法(根据idea)
打开IDEA,挑选Preferences-Plugins-Browserepositories后,在输入框中输入”alibaba”,能够看到回来结果中有”AlibabaJavaCodingGuidelines”。
image
点击插件概况中的”install”按钮,依照其提示即可完结安装,安装完结后需重启IDEA。
功用运用
在项目目录上右键点击也会呈现这两个功用按钮,点击绿色的按钮即可开端扫描代码,或者在工程目录上右键也会呈现检测的功用按钮
image
假如不想悉数扫描,只扫描当前编辑的文件的话,在当前文件面板中点击右键也会呈现此功用按钮。
image
前面说的两种方法是手动检测,插件也供给了实时监测的功用,此功用默许开启,一旦开启则会在你编写代码时就会实时监测,一旦有不符合标准的句子就会呈现过错提示。

java

阿里巴巴java开发手册代码规范

1、命名风格
1)【强制】代码中的命名均不能以下划线或美元符号开端,也不能以下划线或美元符号完毕。
反例:
_name,$name,__name
2)【强制】代码中的命名制止运用拼音与英文混合的办法,更不答应直接运用中文的办法。
阐明:正确的英文拼写和语法可以让阅览者易于了解,防止歧义。留意,纯拼音命名办法更要防止选用。
正例:renminbi/alibaba/taobao/youku/hangzhou等国际通用的称号,可视同英文。
反例:DaZhePromotion[打折]/getPingfenByName()[评分]/int某变量=3
3)【强制】类名运用UpperCamelCase风格,但以下景象破例:DO/BO/DTO/VO/AO/PO/UID等。
正例:JavaServerlessPlatform/UserDO/XmlService/TcpUdpDeal/TaPromotion
反例:javaserverlessplatform/UserDo/XMLService/TCPUDPDeal/TAPromotion
4)【强制】办法名、参数名、成员变量、局部变量都共同运用lowerCamelCase风格,有必要遵从驼峰办法。
正例:localValue/getHttpMessage()/inputUserId
5)【强制】常量命名悉数大写,单词间用下划线离隔,力求语义表达完整清楚,不要嫌姓名长。
正例:MAX_STOCK_COUNT/CACHE_EXPIRED_TIME
反例:MAX_COUNT/EXPIRED_TIME
6)【强制】抽象类命名运用Abstract或Base最初;反常类命名运用Exception完毕;测验类命名以它要测验的类的称号开端,以Test完毕。
7)【强制】类型与中括号紧挨相连来表明数组。
正例:界说整形数组int[]arrayDemo;
反例:在main参数中,运用Stringargs[]来界说。
8)【强制】POJO类中布尔类型变量都不要加is前缀,不然部分结构解析会引起序列化过错。
阐明:在本文MySQL规约中的建表约定榜首条,表达是与否的值选用is_xxx的命名办法,所以,需求在设置从is_xxx到xxx的映射联系。
反例:界说为底子数据类型BooleanisDeleted的特色,它的办法也是isDeleted(),RPC结构在反向解析的时分,“误以为”对应的特色称号是deleted,导致特色获取不到,进而抛出反常。
9)【强制】包名共同运用小写,点分隔符之间有且仅有一个天然语义的英语单词。包名共同运用奇数办法,可是类名假如有复数含义,类名可以运用复数办法。
正例:运用东西类包名为com.alibaba.ai.util、类名为MessageUtils(此规矩参阅spring的结构结构)
10)【强制】防止在子父类的成员变量之间、或许不同代码块的局部变量之间选用彻底相同的命名,使可读性下降。
阐明:子类、父类成员变量名相同,即便是public类型的变量也是可以经过编译,而局部变量在同一办法内的不同代码块中同名也是合法的,可是要防止运用。关于非setter/getter的参数称号也要防止与成员变量称号相同。
反例:
publicclassConfusingName{
publicintage;//非setter/getter的参数称号,不答应与本类成员变量同名
publicvoidgetData(Stringalibaba){
if(condition){
finalintmoney=531;//…
}
for(inti=0;i<10;i++){
//在同一办法体中,不答应与其它代码块中的money命名相同
finalintmoney=615;//…
}
}
}
classSonextendsConfusingName{
//不答应与父类的成员变量称号相同publicintage;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
11)【强制】根绝彻底不标准的缩写,防止望文不知义。
反例:AbstractClass“缩写”命名成AbsClass;condition“缩写”命名成condi,此类随意缩写严峻下降了代码的可阅览性。
12)【引荐】为了到达代码自解说的方针,任何自界说编程元素在命名时,运用尽量完整的单词组合来表达其意。
正例:在JDK中,表达原子更新的类名为:AtomicReferenceFieldUpdater。
反例:inta的随意命名办法。
13)【引荐】在常量与变量的命名时,表明类型的名词放在词尾,以进步辨识度。
正例:startTime/workQueue/nameList/TERMINATED_THREAD_COUNT
反例:startedAt/QueueOfWork/listName/COUNT_TERMINATED_THREAD
14)【引荐】假如模块、接口、类、办法运用了规划办法,在命名时需表现出详细办法。
阐明:将规划办法表现在姓名中,有利于阅览者快速了解架构规划理念。
正例:
publicclassOrderFactory;
publicclassLoginProxy;
publicclassResourceObserver;
15)【引荐】接口类中的办法和特色不要加任何修饰符号(public也不要加),坚持代码的简洁性,并加上有用的Javadoc注释。尽量不要在接口里界说变量,假如必定要界说变量,必定是与接口办法相关,而且是整个运用的基础常量。
正例:
接口办法签名voidcommit();
接口基础常量StringCOMPANY=“alibaba”;
反例:接口办法界说publicabstractvoidf();
阐明:JDK8中接口答应有默许完结,那么这个default办法,是对全部完结类都有价值的默许完结。
接口和完结类的命名有两套规矩:
【强制】关于Service和DAO类,依据SOA的理念,暴露出来的服有必要定是接口,内部的完结类用Impl的后缀与接口区别。
正例:CacheServiceImpl完结CacheService接口。
16)【引荐】假如是描绘才干的接口称号,取对应的描绘词为接口名(一般是–able的描绘词)。
正例:AbstractTranslator完结Translatable接口。
【参阅】枚举类名带上Enum后缀,枚举成员称号需求全大写,单词间用下划线离隔。
阐明:枚举其实便是特别的类,域成员均为常量,且结构办法被默许强制是私有。
正例:枚举姓名为ProcessStatusEnum的成员称号:SUCCESS/UNKNOWN_REASON。
【参阅】各层命名规约:
Service/DAO层办法命名规约
获取单个方针的办法用get做前缀。
获取多个方针的办法用list做前缀,复数办法完毕如:listObjects。
获取计算值的办法用count做前缀。
刺进的办法用save/insert做前缀。
删去的办法用remove/delete做前缀。
修正的办法用update做前缀。
领域模型命名规约
数据方针:xxxDO,xxx即为数据表名。
数据传输方针:xxxDTO,xxx为业务领域相关的称号。
展现方针:xxxVO,xxx一般为网页称号。
POJO是DO/DTO/BO/VO的总称,制止命名成xxxPOJO。
2、常量界说
1)【强制】不答应任何魔法值(即未经预先界说的常量)直接呈现在代码中。
反例:
Stringkey=“Id#taobao_”+tradeId;cache.put(key,value);//缓存get时,由于在代码仿制时,漏掉下划线,导致缓存击穿而呈现问题
2)【强制】在long或许Long赋值时,数值后运用大写的L,不能是小写的l,小写简略跟数字1混杂,形成误解。
阐明:Longa=2l;写的是数字的21,还是Long型的2
3)【引荐】不要运用一个常量类保护全部常量,要按常量功用进行归类,分隔保护。
阐明:大而全的常量类,杂乱无章,运用查找功用才干定位到修正的常量,不利于了解和保护。
正例:缓存相关常量放在类CacheConsts下;体系装备相关常量放在类ConfigConsts下。
4)【引荐】常量的复用层次有五层:跨运用同享常量、运用内同享常量、子工程内同享常量、包内同享常量、类内同享常量。
跨运用同享常量:放置在二方库中,一般是client.jar中的constant目录下。
运用内同享常量:放置在一方库中,一般是子模块中的constant目录下。
反例:易懂变量也要共同界说成运用内同享常量,两位工程师在两个类中别离界说了“YES”的变量:
类A中:publicstaticfinalStringYES=“yes”;
类B中:publicstaticfinalStringYES=“y”;
A.YES.equals(B.YES),预期是true,但实践回来为false,导致线上问题。
子工程内部同享常量:即在当时子工程的constant目录下。
包内同享常量:即在当时包下独自的constant目录下。
类内同享常量:直接在类内部privatestaticfinal界说。
5)【引荐】假如变量值仅在一个固定规模内变化用enum类型来界说。
阐明:假如存在称号之外的延伸特色应运用enum类型,下面正例中的数字便是延伸信息,表明一年中的第几个季节。
正例:
publicenumSeasonEnum{
SPRING(1),
SUMMER(2),
AUTUMN(3),
WINTER(4);
privateintseq;
SeasonEnum(intseq){
this.seq=seq;
}
publicintgetSeq(){
returnseq;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
3、代码格局
1)【强制】假如是大括号内为空,则简洁地写成{}即可,大括号中心无需换行和空格;假如是非空代码块则:
左大括号前不换行。
左大括号后换行。
右大括号前换行。
右大括号后还有else等代码则不换行;表明终止的右大括号后有必要换行。
2)【强制】左小括号和字符之间不呈现空格;相同,右小括号和字符之间也不呈现空格;而左大括号前需求空格。详见第5条下方正例提示。
反例:if(空格a==b空格)
3)【强制】if/for/while/switch/do等保留字与括号之间都有必要加空格。
4)【强制】任何二目、三目运算符的左右两头都需求加一个空格。
阐明:运算符包含赋值运算符=、逻辑运算符&&、加减乘除符号等。
5)【强制】选用4个空格缩进,制止运用tab字符。
阐明:假如运用tab缩进,有必要设置1个tab为4个空格。IDEA设置tab为4个空格时,请勿勾选Usetabcharacter;而在eclipse中,有必要勾选insertspacesfortabs。
正例:(涉及1-5点)
publicstaticvoidmain(Stringargs[]){
//缩进4个空格
Stringsay=”hello”;
//运算符的左右有必要有一个空格
intflag=0;
//要害词if与括号之间有必要有一个空格,括号内f与左括号,1与右括号不需求空格
if(flag==0){
System.out.println(say);
}
//左大括号前加空格且不换行;左大括号后换行
if(flag==1){
System.out.println(“world”);
//右大括号前换行,右大括号后有else,不必换行
}else{
System.out.println(“ok”);
//右大括号做为完毕,有必要换行
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
6)【强制】注释的双斜线与注释内容之间有且仅有一个空格。
正例:
//这是示例注释,请留意在双斜线之后有一个空格
Stringparam=newString();
7)【强制】在进行类型强制转化时,右括号与强制转化值之间不需求任何空格离隔。
正例:
first=1000000000000L;
intsecond=(int)first+2;
1
2
强制】单行字符数限不超越120个,超出需求换行时遵从如下准则:
1)第二行相对一缩进4个空格,从第三行开端不再持续缩进参阅示例。
2)运算符与下文一同换行。
3)办法调用的点符号与下文一同换行。
4)在多个参数超长,逗号后进行换行。
5)在括号前不要换行,见反例。
正例:
StringBuffersb=newStringBuffer();
//超越120个字符的状况下,换行缩进4个空格,而且办法前的点符号一同换行
sb.append(“zi”).append(“xin”)…
.append(“huang”);
反例:
StringBuffersb=newStringBuffer();
//超越120个字符的状况下,不要在括号前换行
sb.append(“zi”).append(“xin”)…append
(“huang”);
//参数许多的办法调用或许超越120个字符,不要在逗号前换行
method(args1,args2,args3,…
,argsX);
1
2
3
4
5
6
7
8
9
10
11
12
13
9)【强制】办法参数在界说和传入时,多个参数逗号后边有必要加空格。
正例:下例中实参的args1,后边有必要要有一个空格。
method(args1,args2,args3);
1
10)【强制】IDE的textfileencoding设置为UTF-8;IDE中文件的换行符运用Unix格局,不要运用Windows格局。
11)【引荐】单个办法的总行数不超越80行。
阐明:除注释之外的办法签名、左右大括号、办法内代码、空行、回车及任何不行见字符的总行数不超越80行。
正例:代码逻辑辨明红花和绿叶,特性和共性,绿叶逻辑独自出来成为额定办法,使主干代码愈加明晰;共性逻辑抽取成为共性办法,便于复用和保护。
12)【引荐】没有必要添加若干空格来使变量的赋值等号与上一行对应方位的等号对齐。
正例:
inta=3;
longb=4L;
floatc=5F;
StringBuffersb=newStringBuffer();
1
2
3
4
5
6
7
阐明:添加sb这个变量,假如需求对齐,则给one、two、three都要添加几个空格,在变量比较多的状况下,是十分负担的作业。
13)【引荐】不同逻辑、不同语义、不同业务的代码之间刺进一个空行分离隔来以进步可读性。
阐明:任何景象,没有必要刺进多个空行进行离隔。
4、OOP规约
1)【强制】防止经过一个类的方针引证拜访此类的静态变量或静态办法,无谓添加编译器解析成本,直接用类名来拜访即可。
2)【强制】全部的覆写办法,有必要加@Override注解。
阐明:getObject()与get0bject()的问题。一个是字母的O,一个是数字的0,加@Override可以准确判别是否掩盖成功。别的,假如在抽象类中对办法签名进行修正,其完结类会立刻编译报错。
3)【强制】相同参数类型,相同业务含义,才可以运用Java的可变参数,防止运用Object。
阐明:可变参数有必要放置在参数列表的最终。(发起同学们尽量不必可变参数编程)
正例:
publicListlistUsers(Stringtype,Long…ids){…}
1
4)【强制】外部正在调用或许二方库依靠的接口,不答应修正办法签名,防止对接口调用方发生影响。接口过期有必要加@Deprecated注解,并明晰地阐明选用的新接口或许新服务是什么。
5)【强制】不能运用过期的类或办法。
阐明:java.net.URLDecoder中的办法decode(StringencodeStr)这个办法现已过期,应该运用双参数decode(Stringsource,Stringencode)。接口供给方既然明晰是过期接口,那么有义务一同供给新的接口;作为调用方来说,有义务去考证过期办法的新完结是什么。
6)【强制】Object的equals办法简略抛空指针反常,应运用常量或确认有值的方针来调用equals。
正例:“test”.equals(object);
反例:object.equals(“test”);
阐明:引荐运用java.util.Objects#equals(JDK7引进的东西类)。
7)【强制】全部整型包装类方针之间值的比较,悉数运用equals办法比较。
阐明:关于Integervar=?在-128至127规模内的赋值,Integer方针是在IntegerCache.cache发生,会复用已有方针,这个区间内的Integer值可以直接运用==进行判别,可是这个区间之外的全部数据,都会在堆上发生,并不会复用已有方针,这是一个大坑,引荐运用equals办法进行判别。
8)【强制】浮点数之间的等值判别,底子数据类型不能用==来比较,包装数据类型不能用equals来判别。
阐明:浮点数选用“尾数+阶码”的编码办法,类似于科学计数法的“有用数字+指数”的表明办法。二进制无法准确表明大部分的十进制小数,详细原理参阅《码出高效》。
反例:
floata=1.0f-0.9f;
floatb=0.9f-0.8f;
if(a==b){
//预期进入此代码快,履行其它业务逻辑
//但事实上a==b的成果为false
}
Floatx=Float.valueOf(a);
Floaty=Float.valueOf(b);
if(x.equals(y)){
//预期进入此代码快,履行其它业务逻辑
//但事实上equals的成果为false
}
1
2
3
4
5
6
7
8
9
10
11
12
正例:
指定一个差错规模,两个浮点数的差值在此规模之内,则以为是持平的。
floata=1.0f-0.9f;
floatb=0.9f-0.8f;
floatdiff=1e-6f;
if(Math.abs(a-b)<diff){
System.out.println(“true”);
}
1
2
3
4
5
6
运用BigDecimal来界说值,再进行浮点数的运算操作。
BigDecimala=newBigDecimal(“1.0”);
BigDecimalb=newBigDecimal(“0.9”);
BigDecimalc=newBigDecimal(“0.8”);
BigDecimalx=a.subtract(b);
BigDecimaly=b.subtract(c);
if(x.equals(y)){
System.out.println(“true”);
}
1
2
3
4
5
6
7
8
9)【强制】界说数据方针DO类时,特色类型要与数据库字段类型相匹配。
正例:数据库字段的bigint有必要与类特色的Long类型相对应。
反例:某个案例的数据库表id字段界说类型bigintunsigned,实践类方针特色为Integer,跟着id越来越大,超越Integer的表明规模而溢出成为负数。
10)【强制】为了防止精度丢失,制止运用结构办法BigDecimal(double)的办法把double值转化为BigDecimal方针。
阐明:BigDecimal(double)存在精度丢失危险,在准确核算或值比较的场景中或许会导致业务逻辑反常。
如:BigDecimalg=newBigDecimal(0.1f);实践的存储值为:0.10000000149
正例:优先引荐入参为String的结构办法,或运用BigDecimal的valueOf办法,此办法内部其实履行了Double的toString,而Double的toString按double的实践能表达的精度对尾数进行了切断。
BigDecimalrecommend1=newBigDecimal(“0.1”);
BigDecimalrecommend2=BigDecimal.valueOf(0.1);
关于底子数据类型与包装数据类型的运用标准如下:
11)【强制】全部的POJO类特色有必要运用包装数据类型。
12)【强制】RPC办法的回来值和参数有必要运用包装数据类型。
13)【引荐】全部的局部变量运用底子数据类型。
阐明:POJO类特色没有初值是提醒运用者在需求运用时,有必要自己显式地进行赋值,任何NPE问题,或许入库查看,都由运用者来确保。
正例:数据库的查询成果或许是null,由于主动拆箱,用底子数据类型接收有NPE危险。
反例:比方显现成交总额涨跌状况,即正负x%,x为底子数据类型,调用的RPC服务,调用不成功时,回来的是默许值,页面显现为0%,这是不合理的,应该显现成中划线。所以包装数据类型的null值,可以表明额定的信息,如:长途调用失利,反常退出。
14)【强制】界说DO/DTO/VO等POJO类时,不要设定任何特色默许值。
反例:POJO类的createTime默许值为newDate(),可是这个特色在数据提取时并没有置入详细值,在更新其它字段时又附带更新了此字段,导致创立时刻被修正成当时时刻。
15)【强制】序列化类新增特色时,请不要修正serialVersionUID字段,防止反序列失利;假如彻底不兼容晋级,防止反序列化紊乱,那么请修正serialVersionUID值。
阐明:留意serialVersionUID不共同会抛出序列化运转时反常。
16)【强制】结构办法里面制止参加任何业务逻辑,假如有初始化逻辑,请放在init办法中。
17)【强制】POJO类有必要写toString办法。运用IDE中的东西:source>generatetoString时,假如承继了另一个POJO类,留意在前面加一下super.toString。
阐明:在办法履行抛出反常时,可以直接调用POJO的toString()办法打印其特色值,便于排查问题。
18)【强制】制止在POJO类中,一同存在对应特色xxx的isXxx()和getXxx()办法。
阐明:结构在调用特色xxx的提取办法时,并不能确认哪个办法必定是被优先调用到。
19)【引荐】运用索引拜访用String的split办法得到的数组时,需做最终一个分隔符后有无内容的查看,不然会有抛IndexOutOfBoundsException的危险。
阐明:
Stringstr=”a,b,c,,”;String[]ary=str.split(“,”);
1
//预期大于3,成果是3System.out.println(ary.length);
20)【引荐】当一个类有多个结构办法,或许多个同名办法,这些办法应该按次第放置在一同,便于阅览,此条规矩优先于下一条。
21)【引荐】类内办法界说的次第顺次是:公有办法或保护办法>私有办法>getter/setter办法。
阐明:公有办法是类的调用者和保护者最关怀的办法,首屏展现最好;保护办法尽管仅仅子类关怀,也或许是“模板规划办法”下的中心办法;而私有办法外部一般不需求特别关怀,是一个黑盒完结;由于承载的信息价值较低,全部Service和DAO的getter/setter办法放在类体最终。
22)【引荐】setter办法中,参数称号与类成员变量称号共同,this.成员名=参数名。在getter/setter办法中,不要添加业务逻辑,添加排查问题的难度。
反例:
publicIntegergetData(){
if(condition){
returnthis.data+100;
}else{
returnthis.data-100;
}
}
1
2
3
4
5
6
7
23)【引荐】循环体内,字符串的衔接办法,运用StringBuilder的append办法进行扩展。
阐明:下例中,反编译出的字节码文件显现每次循环都会new出一个StringBuilder方针,然后进行append操作,最终经过toString办法回来String方针,形成内存资源糟蹋。
反例:
Stringstr=”start”;
for(
inti=0;i<100;i++){
str=str+”hello”;
}
1
2
3
4
5
24)【引荐】final可以声明类、成员变量、办法、以及本地变量,下列状况运用final要害字:
不答应被承继的类,如:String类。
不答应修正引证的域方针。
不答应被覆写的办法,如:POJO类的setter办法。
不答应运转进程中从头赋值的局部变量。
防止上下文重复运用一个变量,运用final可以强制从头界说一个变量,方便更好地进行重构。
25)【引荐】慎用Object的clone办法来仿制方针。
阐明:方针clone办法默许是浅仿制,若想完结深仿制需覆写clone办法完结域方针的深度遍历式仿制。
26)【引荐】类成员与办法拜访操控从严:
假如不答应外部直接经过new来创立方针,那么结构办法有必要是private。
东西类不答应有public或default结构办法。
类非static成员变量而且与子类同享,有必要是protected。
类非static成员变量而且仅在本类运用,有必要是private。
类static成员变量假如仅在本类运用,有必要是private。
若是static成员变量,考虑是否为final。
类成员办法只供类内部调用,有必要是private。
类成员办法只对承继类公开,那么限制为protected。
阐明:任何类、办法、参数、变量,严控拜访规模。过于宽泛的拜访规模,不利于模块解耦。考虑:假如是一个private的办法,想删去就删去,可是一个public的service成员办法或成员变量,删去一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视野内,变量效果域太大,无限制的到处跑,那么你会担心的。
5、调集处理
1)【强制】关于hashCode和equals的处理,遵从如下规矩:
只需覆写equals,就有必要覆写hashCode。
由于Set存储的是不重复的方针,依据hashCode和equals进行判别,所以Set存储的方针有必要覆写这两个办法。
假如自界说方针作为Map的键,那么有必要覆写hashCode和equals。
阐明:String已覆写hashCode和equals办法,所以咱们可以愉快地运用String方针作为key来运用。
2)【强制】ArrayList的subList成果不行强转成ArrayList,不然会抛出ClassCastException异常,即java.util.RandomAccessSubListcannotbecasttojava.util.ArrayList。
阐明:subList回来的是ArrayList的内部类SubList,并不是ArrayList而是ArrayList的一个视图,关于SubList子列表的全部操作最终会反映到原列表上。
3)【强制】运用Map的办法keySet()/values()/entrySet()回来调集方针时,不行以对其进行添加元素操作,不然会抛出UnsupportedOperationException反常。
4)【强制】Collections类回来的方针,如:emptyList()/singletonList()等都是immutablelist,不行对其进行添加或许删去元素的操作。
反例:假如查询无成果,回来Collections.emptyList()空调集方针,调用方一旦进行了添加元素的操作,就会触发UnsupportedOperationException反常。
5)【强制】在subList场景中,高度留意对原调集元素的添加或删去,均会导致子列表的遍历、添加、删去发生ConcurrentModificationException反常。
6)【强制】运用调集转数组的办法,有必要运用调集的toArray(T[]array),传入的是类型彻底共同、长度为0的空数组。
反例:直接运用toArray无参办法存在问题,此办法回来值只能是Object[]类,若强转其它类型数组将呈现ClassCastException过错。
正例:
Listlist=newArrayList<>(2);
list.add(“guan”);
list.add(“bao”);
String[]array=list.toArray(newString[0]);
1
2
3
4
阐明:运用toArray带参办法,数组空间巨细的length:
等于0,动态创立与size相同的数组,功用最好。
大于0但小于size,从头创立巨细等于size的数组,添加GC负担。
等于size,在高并发状况下,数组创立完结之后,size正在变大的状况下,负面影响与上相同。
大于size,空间糟蹋,且在size处刺进null值,存在NPE危险。
7)【强制】在运用Collection接口任何完结类的addAll()办法时,都要对输入的调集参数进行NPE判别。
阐明:在ArrayList#addAll办法的榜首行代码即Object[]a=c.toArray();其间c为输入调集参数,假如为null,则直接抛出反常。
8)【强制】运用东西类Arrays.asList()把数组转化成调集时,不能运用其修正调集相关的办法,它的add/remove/clear办法会抛出UnsupportedOperationException反常。
阐明:asList的回来方针是一个Arrays内部类,并没有完结调集的修正办法。Arrays.asList表现的是适配器办法,仅仅转化接口,后台的数据仍是数组。
String[]str=newString[]{“yang”,”hao”};
Listlist=Arrays.asList(str);
1
2
榜首种状况:list.add(“yangguanbao”);运转时反常。
第二种状况:str[0]=“changed”;也会随之修正,反之亦然。
9)【强制】泛型通配符来接收回来的数据,此写法的泛型调集不能运用add方法,而不能运用get办法,作为接口调用赋值时易犯错。
阐明:扩展说一下PECS(ProducerExtendsConsumerSuper)准则:
榜首、频频往外读取内容的,适合用。
第二、常常往里刺进的,适合用
10)【强制】在无泛型限制界说的调集赋值给泛型限制的调集时,在运用调集元素时,需求进行instanceof判别,防止抛出ClassCastException反常。
阐明:究竟泛型是在JDK5后才呈现,考虑到向前兼容,编译器是答应非泛型调集与泛型调集互相赋值。
反例:
Listgenerics=null;
ListnotGenerics=newArrayList(10);
notGenerics.add(newObject());
notGenerics.add(newInteger(1));
generics=notGenerics;
//此处抛出ClassCastException反常Stringstring=generics.get(0);
1
2
3
4
5
6
11)【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请运用Iterator办法,假如并发操作,需求对Iterator方针加锁。
正例:
Listlist=newArrayList<>();
list.add(“1”);
list.add(“2”);
Iteratoriterator=list.iterator();
while(iterator.hasNext()){
Stringitem=iterator.next();
if(删去元素的条件){
iterator.remove();
}
}
1
2
3
4
5
6
7
8
9
10
反例:
for(Stringitem:list){
if(“1″.equals(item)){
list.remove(item);
}
}
1
2
3
4
5
阐明:以上代码的履行成果必定会出乎大家的意料,那么试一下把“1”换成“2”,会是相同的成果吗?
12)【强制】在JDK7版别及以上,Comparator完结类要满意如下三个条件,不然Arrays.sort,Collections.sort会抛IllegalArgumentException反常。
阐明:三个条件如下
x,y的比较成果和y,x的比较成果相反。
x>y,y>z,则x>z。
x=y,则x,z比较成果和y,z比较成果相同。
反例:下例中没有处理持平的状况,交换两个方针判别成果并不互反,不契合榜首个条件,在实践运用中或许会呈现反常。
newComparator(){
@Overridepublicintcompare(Studento1,Studento2){
returno1.getId()>o2.getId()?1:-1;
}
};
1
2
3
4
5
13)【引荐】调集泛型界说时,在JDK7及以上,运用diamond语法或全省掉。
阐明:菱形泛型,即diamond,直接运用<>来指代前边现已指定的类型。
正例:
diamond办法,即<>
HashMapuserCache=newHashMap<>(16);
//全省掉办法ArrayListusers=newArrayList(10);
1
2
3
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值的状况,如下表格:
调集类
Key
Value
Super
阐明
Hashtable
不答应为null
不答应为null
Dictionary
线程安全
ConcurrentHashMap
不答应为null
不答应为null
AbstractMap
锁分段技能(JDK8:CAS)
TreeMap
不答应为null
答应为null
AbstractMap
线程不安全
HashMap
答应为null
答应为null
AbstractMap
线程不安全
反例:由于HashMap的搅扰,许多人以为ConcurrentHashMap是可以置入null值,而事实上,存储null值时会抛出NPE反常。
17)【参阅】合理运用好调集的有序性(sort)和安稳性(order),防止调集的无序性(unsort)和不安稳性(unorder)带来的负面影响。
阐明:有序性是指遍历的成果是按某种比较规矩顺次摆放的。安稳性指调集每次遍历的元素次第是必定的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。
18)【参阅】运用Set元素仅有的特性,可以快速对一个调集进行去重操作,防止运用List的contains办法进行遍历、比照、去重操作。
6、并发处理
1)【强制】获取单例方针需求确保线程安全,其间的办法也要确保线程安全。
阐明:资源驱动类、东西类、单例工厂类都需求留意。
2)【强制】创立线程或线程池时请指定有含义的线程称号,方便犯错时回溯。
正例:自界说线程工厂,而且依据外部特征进行分组,比方机房信息。
publicclassUserThreadFactoryimplementsThreadFactory{
privatefinalStringnamePrefix;
privatefinalAtomicIntegernextId=newAtomicInteger(1);
//界说线程组称号,在jstack问题排查时,十分有协助
UserThreadFactory(StringwhatFeaturOfGroup){
namePrefix=”FromUserThreadFactory’s”+whatFeaturOfGroup+”-Worker-“;
}
@Override
publicThreadnewThread(Runnabletask){
Stringname=namePrefix+nextId.getAndIncrement();
Threadthread=newThread(null,task,name,0,false);
System.out.println(thread.getName());
returnthread;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3)【强制】线程资源有必要经过线程池供给,不答应在运用中自行显式创立线程。
阐明:线程池的优点是削减在创立和销毁线程上所耗费的时刻以及体系资源的开支,处理资源不足的问题。假如不运用线程池,有或许形成体系创立大量同类线程而导致耗费完内存或许“过度切换”的问题。
4)【强制】线程池不答应运用Executors去创立,而是经过ThreadPoolExecutor的办法,这样的处理办法让写的同学愈加明晰线程池的运转规矩,躲避资源耗尽的危险。
阐明:Executors回来的线程池方针的弊端如下:
FixedThreadPool和SingleThreadPool:
答应的恳求行列长度为Integer.MAX_VALUE,或许会堆积大量的恳求,从而导致OOM。
CachedThreadPool:
答应的创立线程数量为Integer.MAX_VALUE,或许会创立大量的线程,从而导致OOM。
5)【强制】SimpleDateFormat是线程不安全的类,一般不要界说为static变量,假如界说为static,有必要加锁,或许运用DateUtils东西类。
正例:留意线程安全,运用DateUtils。亦引荐如下处理:
privatestaticfinalThreadLocaldf=newThreadLocal(){
@Override
protectedDateFormatinitialValue(){
returnnewSimpleDateFormat(“yyyy-MM-dd”);
}
};
1
2
3
4
5
6
阐明:假如是JDK8的运用,可以运用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,官方给出的解说:simplebeautifulstrongimmutablethread-safe。
6)【强制】有必要回收自界说的ThreadLocal变量,尤其在线程池场景下,线程常常会被复用,假如不整理自界说的ThreadLocal变量,或许会影响后续业务逻辑和形成内存泄露等问题。尽量在署理中运用try-finally块进行回收。
正例:
ThreadLocal.set(userInfo);
try{
//…
}finally{
objectThreadLocal.remove();
}
1
2
3
4
5
6
7)【强制】高并发时,同步调用应该去考量锁的功用损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个办法体;能用方针锁,就不要用类锁。
阐明:尽或许使加锁的代码块作业量尽或许的小,防止在锁代码块中调用RPC办法。
8)【强制】对多个资源、数据库表、方针一同加锁时,需求坚持共同的加锁次第,不然或许会形成死锁。
阐明:线程一需求对表A、B、C顺次悉数加锁后才可以进行更新操作,那么线程二的加锁次第也有必要是A、B、C,不然或许呈现死锁。
9)【强制】在运用堵塞等候获取锁的办法中,有必要在try代码块之外,而且在加锁办法与try代码块之间没有任何或许抛出反常的办法调用,防止加锁成功后,在finally中无法解锁。
阐明一:假如在lock办法与try代码块之间的办法调用抛出反常,那么无法解锁,形成其它线程无法成功获取锁。
阐明二:假如lock办法在try代码块之内,或许由于其它办法抛出反常,导致在finally代码块中,unlock对未加锁的方针解锁,它会调用AQS的tryRelease办法(取决于详细完结类),抛出IllegalMonitorStateException反常。
阐明三:在Lock方针的lock办法完结中或许抛出unchecked反常,发生的后果与阐明二相同。
正例:
Locklock=newXxxLock();
//…lock.lock();
try{
doSomething();
doOthers();
}finally{
lock.unlock();
}
1
2
3
4
5
6
7
8
反例:
Locklock=newXxxLock();
//…
try{
//假如此处抛出反常,则直接履行finally代码块
doSomething();
//无论加锁是否成功,
finally代码块都会履行
lock.lock();
doOthers();
}finally{
lock.unlock();
}
1
2
3
4
5
6
7
8
9
10
11
12
9)【强制】在运用尝试机制来获取锁的办法中,进入业务代码块之前,有必要先判别当时线程是否持有锁。锁的开释规矩与锁的堵塞等候办法相同。
阐明:Lock方针的unlock办法在履行时,它会调用AQS的tryRelease办法(取决于详细完结类),假如当时线程不持有锁,则抛出IllegalMonitorStateException反常。
正例:
Locklock=newXxxLock();
//…booleanisLocked=lock.tryLock();
if(isLocked){
try{
doSomething();
doOthers();
}finally{
lock.unlock();
}
}
1
2
3
4
5
6
7
8
9
10
10)【强制】并发修正同一记载时,防止更新丢失,需求加锁。要么在运用层加锁,要么在缓存加锁,要么在数据库层运用达观锁,运用version作为更新依据。
阐明:假如每次拜访冲突概率小于20%,引荐运用达观锁,不然运用失望锁。达观锁的重试次数不得小于3次。
11)【强制】多线程并行处理定时任务时,Timer运转多个TimeTask时,只需其间之一没有捕获抛出的反常,其它任务便会主动终止运转,假如在处理定时任务时运用ScheduledExecutorService则没有这个问题。
12)【引荐】资金相关的金融灵敏信息,运用失望锁战略。
阐明:达观锁在获得锁的一同现已完结了更新操作,校验逻辑简略呈现漏洞,别的,达观锁对冲突的处理战略有较杂乱的要求,处理不妥简略形成体系压力或数据反常,所以资金相关的金融灵敏信息不主张运用达观锁更新。
13)【引荐】运用CountDownLatch进行异步转同步操作,每个线程退出前有必要调用countDown办法,线程履行代码留意catch反常,确保countDown办法被履行到,防止主线程无法履行至await办法,直到超时才回来成果。
阐明:留意,子线程抛出反常库房,不能在主线程try-catch到。
14)【引荐】防止Random实例被多线程运用,尽管同享该实例是线程安全的,但会因竞争同一seed导致的功用下降。
阐明:Random实例包含java.util.Random的实例或许Math.random()的办法。
正例:在JDK7之后,可以直接运用APIThreadLocalRandom,而在JDK7之前,需求编码确保每个线程持有一个实例。
15)【引荐】在并发场景下,经过双重查看锁(double-checkedlocking)完结推迟初始化的优化问题危险(可参阅The“Double-CheckedLockingisBroken”Declaration),引荐处理方案中较为简略一种(适用于JDK5及以上版别),将方针特色声明为volatile型。
反例:
classLazyInitDemo{
privateHelperhelper=null;
publicHelpergetHelper(){
if(helper==null)
synchronized(this){
if(helper==null)
helper=newHelper();
}
returnhelper;
}
//othermethodsandfields…
}
1
2
3
4
5
6
7
8
9
10
11
12
16)【参阅】volatile处理多线程内存不行见问题。关于一写多读,是可以处理变量同步问题,但
是假如多写,相同无法处理线程安全问题。
阐明:假如是count++操作,运用如下类完结:
AtomicIntegercount=newAtomicInteger();
count.addAndGet(1);
假如是JDK8,引荐运用LongAdder方针,比AtomicLong功用更好(削减达观
锁的重试次数)。
17)【参阅】HashMap在容量不够进行resize时由于高并发或许呈现死链,导致CPU飙升,在
开发进程中可以运用其它数据结构或加锁来躲避此危险。
18)【参阅】ThreadLocal方针运用static修饰,ThreadLocal无法处理同享方针的更新问题。
阐明:这个变量是针对一个线程内全部操作同享的,所以设置为静态变量,全部此类实例同享此静态变
量,也便是说在类榜首次被运用时装载,只分配一块存储空间,全部此类的方针(只需是这个线程内界说
的)都可以操控这个变量。
7、操控句子
【强制】在一个switch块内,每个case要么经过continue/break/return等来终止,要么注释阐明程序将持续履行到哪一个case为止;在一个switch块内,都有必要包含一个default句子而且放在最终,即便它什么代码也没有。
阐明:留意break是退出switch句子块,而return是退出办法体。
2)【强制】当switch括号内的变量类型为String而且此变量为外部参数时,有必要先进行null判别。
反例:猜猜下面的代码输出是什么?
publicclassSwitchString{
publicstaticvoidmain(String[]args){
method(null);
}
publicstaticvoidmethod(Stringparam){
switch(param){
//必定不是进入这儿
case”sth”:System.out.println(“it’ssth”);
break;
//也不是进入这儿
case”null”:System.out.println(“it’snull”);
break;
//也不是进入这儿
default:
System.out.println(“default”);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3)【强制】在if/else/for/while/do句子中有必要运用大括号。
阐明:即便只要一行代码,防止选用单行的编码办法:if(condition)statements;
4)【强制】在高并发场景中,防止运用”等于”判别作为中断或退出的条件。
阐明:假如并发操控没有处理好,简略发生等值判别被“击穿”的状况,运用大于或小于的区间判别条件来代替。
反例:判别剩余奖品数量等于0时,终止发放奖品,但由于并发处理过错导致奖品数量瞬间变成了负数,这样的话,活动无法终止。
5)【引荐】表达反常的分支时,少用if-else办法,这种办法可以改写成:
if(condition){
…returnobj;
}
1
2
3
//接着写else的业务逻辑代码;
阐明:假如非运用if()…elseif()…else…办法表达逻辑,防止后续代码保护困难,【强制】请勿超越3层。
正例:超越3层的if-else的逻辑判别代码可以运用卫句子、战略办法、状况办法等来完结,其间卫句子即代码逻辑先考虑失利、反常、中断、退出等直接回来的状况,以办法多个出口的办法,处理代码中判别分支嵌套的问题,这是逆向思维的表现。
示例如下:
publicvoidfindBoyfriend(Manman){
if(man.isUgly()){
System.out.println(“本姑娘是外貌协会的资深会员”);
return;
}
if(man.isPoor()){
System.out.println(“贫贱夫妻百事哀”);
return;
}
if(man.isBadTemper()){
System.out.println(“银河有多远,你就给我滚多远”);
return;
}
System.out.println(“可以先往来一段时刻看看”);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
6)【引荐】除常用办法(如getXxx/isXxx)等外,不要在条件判别中履行其它杂乱的句子,将杂乱逻辑判别的成果赋值给一个有含义的布尔变量名,以进步可读性。
阐明:许多if句子内的逻辑表达式恰当杂乱,与、或、取反混合运算,甚至各种办法纵深调用,了解成本十分高。假如赋值一个十分好了解的布尔变量姓名,则是件令人爽心悦目的作业。
正例:
//伪代码如下
finalbooleanexisted=(file.open(fileName,”w”)!=null)&&(…)||(…);
if(existed){

}
1
2
3
4
反例:
publicfinalvoidacquire(longarg){
if(!tryAcquire(arg)&&acquireQueued(addWaiter(Node.EXCLUSIVE),arg)){
selfInterrupt();
}
}
1
2
3
4
5
7)【引荐】不要在其它表达式(尤其是条件表达式)中,刺进赋值句子。
阐明:赋值点类似于人体的穴道,关于代码的了解至关重要,所以赋值句子需求明晰地独自成为一行。
反例:
publicLockgetLock(booleanfair){
//算术表达式中呈现赋值操作,简略疏忽count值现已被改变
threshold=(count=Integer.MAX_VALUE)-1;
//条件表达式中呈现赋值操作,简略误以为是
sync==fair
return
(sync=fair)?newFairSync():newNonfairSync();
}
1
2
3
4
8)【引荐】循环体中的句子要考量功用,以下操作尽量移至循环体外处理,如界说方针、变量、获取数据库衔接,进行不必要的try-catch操作(这个try-catch是否可以移至循环体外)。
9)【引荐】防止选用取反逻辑运算符。
阐明:取反逻辑不利于快速了解,而且取反逻辑写法必定存在对应的正向逻辑写法。
正例:运用if(x<628)来表达x小于628。
反例:运用if(!(x>=628))来表达x小于628。
10)【引荐】接口入参保护,这种场景常见的是用作批量操作的接口。
【参阅】下列景象,需求进行参数校验:
调用频次低的办法。
履行时刻开支很大的办法。此景象中,参数校验时刻简直可以疏忽不计,但假如由于参数过错导致中心履行回退,或许过错,那得不偿失。
需求极高安稳性和可用性的办法。
对外供给的敞开接口,不管是RPC/API/HTTP接口。
灵敏权限进口。
11)【参阅】下列景象,不需求进行参数校验:
极有或许被循环调用的办法。但在办法阐明里有必要注明外部参数查看要求。
底层调用频度比较高的办法。究竟是像纯净水过滤的最终一道,参数过错不太或许到底层才会暴露问题。一般DAO层与Service层都在同一个运用中,布置在同一台服务器中,所以DAO的参数校验,可以省掉。
被声明成private只会被自己代码所调用的办法,假如可以确认调用办法的代码传入参数现已做过查看或许必定不会有问题,此时可以不校验参数。
8、注释规约
1)【强制】类、类特色、类办法的注释有必要运用Javadoc标准,运用/*内容/格局,不得运用//xxx办法。
阐明:在IDE编辑窗口中,Javadoc办法会提示相关注释,生成Javadoc可以正确输出相应注释;在IDE中,工程调用办法时,不进入办法即可悬浮提示办法、参数、回来值的含义,进步阅览功率。
2)【强制】全部的抽象办法(包含接口中的办法)有必要要用Javadoc注释、除了回来值、参数、反常阐明外,还有必要指出该办法做什么作业,完结什么功用。
阐明:对子类的完结要求,或许调用留意事项,请一同阐明。
3)【强制】全部的类都有必要添加创立者和创立日期
4)【强制】办法内部单行注释,在被注释句子上方另起一行,运用//注释。办法内部多行注释运用/**/注释,留意与代码对齐
5)【强制】全部的枚举类型字段有必要要有注释,阐明每个数据项的用途
6)【引荐】与其“半吊子”英文来注释,不如用中文注释把问题说清楚。专有名词与要害字坚持英文原文即可。
反例:“TCP衔接超时”解说成“传输操控协议衔接超时”,了解反而费脑筋。
7)【引荐】代码修正的一同,注释也要进行相应的修正,尤其是参数、回来值、反常、中心逻辑等的修正。
阐明:代码与注释更新不同步,就像路网与导航软件更新不同步相同,假如导航软件严峻滞后,就失去了导航的含义。
8)【参阅】谨慎注释掉代码。在上方详细阐明,而不是简略地注释掉。假如无用,则删去。
阐明:代码被注释掉有两种或许性:
后续会恢复此段代码逻辑。
永久不必
前者假如没有备注信息,难以知晓注释动机。后者主张直接删掉(代码库房已然保存了历史代码)。
9)【参阅】关于注释的要求
榜首、可以准确反映规划思想和代码逻辑;
第二、可以描绘业务含义,使别的程序员可以迅速了解到代码背后的信息。彻底没有注释的大段代码关于阅览者形同天书,注释是给自己看的,即便隔很长时刻,也能明晰了解当时的思路;注释也是给继任者看的,使其可以快速接替自己的作业。
10)【参阅】好的命名、代码结构是自解说的,注释力求精简准确、表到达位。防止呈现注释的一个极点:过多过滥的注释,代码的逻辑一旦修正,修正注释是恰当大的负担。
反例:
putelephantintofridgeput(elephant,fridge);
办法名put,加上两个有含义的变量名elephant和fridge,现已阐明了这是在干什么,语义明晰的代码不需求额定的注释。
11)【参阅】特别注释符号,请注明符号人与符号时刻。留意及时处理这些符号,经过符号扫描,常常整理此类符号。线上毛病有时分便是来源于这些符号处的代码。
待办事宜(TODO):(符号人,符号时刻,[估计处理时刻])
表明需求完结,但现在还未完结的功用。这实践上是一个Javadoc的标签,现在的Javadoc还没有完结,但现已被广泛运用。只能运用于类,接口和办法(由于它是一个Javadoc标签)。
过错,不能作业(FIXME):(符号人,符号时刻,[估计处理时刻])
在注释顶用FIXME符号某代码是过错的,而且不能作业,需求及时纠正的状况。
9、其它
1)【强制】在运用正则表达式时,运用好其预编译功用,可以有用加快正则匹配速度。
阐明:不要在办法体内界说:Patternpattern=Pattern.compile(“规矩”);
2)【强制】velocity调用POJO类的特色时,直接运用特色名取值即可,模板引擎会主动按标准调用POJO的getXxx(),假如是boolean底子数据类型变量(boolean命名不需求加is前缀),会主动调用isXxx()办法。
阐明:留意假如是Boolean包装类方针,优先调用getXxx()的办法。
3)【强制】后台输送给页面的变量有必要加$!{var}——中心的感叹号。
阐明:假如var等于null或许不存在,那么${var}会直接显现在页面上。
4)【强制】留意Math.random()这个办法回来是double类型,留意取值的规模0≤x<1(可以取到零值,留意除零反常),假如想获取整数类型的随机数,不要将x放大10的若干倍然后取整,直接运用Random方针的nextInt或许nextLong办法。
5)【强制】获取当时毫秒数System.currentTimeMillis();而不是newDate().getTime();
阐明:假如想获取愈加准确的纳秒级时刻值,运用System.nanoTime()的办法。在JDK8中,针对计算时刻等场景,引荐运用Instant类。
6)【强制】日期格局化时,传入pattern中表明年份共同运用小写的y。
阐明:日期格局化时,yyyy表明当天所在的年,而大写的YYYY代表是weekinwhichyear(JDK7之后引进的概念),意思是当天所在的周归于的年份,一周从周日开端,周六完毕,只需本周跨年,回来的YYYY便是下一年。别的需求留意:
表明月份是大写的M
表明分钟则是小写的m
24小时制的是大写的H
12小时制的则是小写的h
正例:表明日期和时刻的格局如下所示:
newSimpleDateFormat(“yyyy-MM-ddHH:mm:ss”);
7)【引荐】不要在视图模板中参加任何杂乱的逻辑。
阐明:依据MVC理论,视图的职责是展现,不要抢模型和操控器的活。
8)【引荐】任何数据结构的结构或初始化,都应指定巨细,防止数据结构无限添加吃光内存。
9)【引荐】及时整理不再运用的代码段或装备信息。
阐明:关于垃圾代码或过期装备,坚决整理洁净,防止程序过度臃肿,代码冗余。
正例:关于暂时被注释掉,后续或许恢复运用的代码片断,在注释代码上方,共同规定运用三个斜杠(///)来阐明注释掉代码的理由。
10、反常日志
1)反常处理
【强制】Java类库中界说的可以经过预查看办法躲避的RuntimeException反常不应该经过catch的办法来处理,比方:NullPointerException,IndexOutOfBoundsException等等。
阐明:无法经过预查看的反常除外,比方,在解析字符串办法的数字时,或许存在数字格局过错,不得不经过catchNumberFormatException来完结。
正例:if(obj!=null){…}
反例:try{obj.method();}catch(NullPointerExceptione){…}
2)【强制】反常不要用来做流程操控,条件操控。
阐明:反常规划的初衷是处理程序运转中的各种意外状况,且反常的处理功率比条件判别办法要低许多。
3)【强制】catch时请辨明安稳代码和非安稳代码,安稳代码指的是无论如何不会犯错的代码。
关于非安稳代码的catch尽或许进行区别反常类型,再做对应的反常处理。
阐明:对大段代码进行try-catch,使程序无法依据不同的反常做出正确的应激反应,也不利于定位问题,这是一种不负职责的表现。
正例:用户注册的场景中,假如用户输入不合法字符,或用户称号已存在,或用户输入暗码过于简略,在程序上作出分门别类的判别,并提示给用户。
4)【强制】捕获反常是为了处理它,不要捕获了却什么都不处理而抛弃之,假如不想处理它,请将该反常抛给它的调用者。最外层的业务运用者,有必要处理反常,将其转化为用户可以了解的内容。
5)【强制】有try块放到了业务代码中,catch反常后,假如需求回滚业务,必定要留意手动回滚业务。
6)【强制】finally块有必要对资源方针、流方针进行关闭,有反常也要做try-catch。
阐明:假如JDK7及以上,可以运用try-with-resources办法。
7)【强制】不要在finally块中运用return。
阐明:try块中的return句子履行成功后,并不立刻回来,而是持续履行finally块中的句子,假如此处存在return句子,则在此直接回来,无情丢掉掉try块中的回来点。
反例:
privateintx=0;
publicintcheckReturn(){
try{
//x等于1,此处不回来
return++x;
}finally{
//回来的成果是2
return++x;
}
}
1
2
3
4
5
6
7
8
9
10
8)【强制】捕获反常与抛反常,有必要是彻底匹配,或许捕获反常是抛反常的父类。
阐明:假如预期对方抛的是绣球,实践接到的是铅球,就会发生意外状况。
9)【强制】在调用RPC、二方包、或动态生成类的相关办法时,捕捉反常有必要运用Throwable类来进行阻拦。
阐明:经过反射机制来调用办法,假如找不到办法,抛出NoSuchMethodException。什么状况会抛出NoSuchMethodError呢?二方包在类冲突时,裁定机制或许导致引进非预期的版别使类的办法签名不匹配,或许在字节码修正结构(比方:ASM)动态创立或修正类时,修正了相应的办法签名。这些状况,即便代码编译期是正确的,但在代码运转期时,会抛出NoSuchMethodError。
10)【引荐】办法的回来值可以为null,不强制回来空调集,或许空方针等,有必要添加注释充分阐明什么状况下会回来null值。
阐明:本手册明晰防止NPE是调用者的职责。即便被调用办法回来空调集或许空方针,对调用者来说,也并非无忧无虑,有必要考虑到长途调用失利、序列化失利、运转时反常等场景回来null的状况。
11)【引荐】防止NPE,是程序员的底子修养,留意NPE发生的场景:
回来类型为底子数据类型,return包装数据类型的方针时,主动拆箱有或许发生NPE。
反例:
publicintf(){
returnInteger方针
}
1
2
3
假如为null,主动解箱抛NPE。
数据库的查询成果或许为null。
调集里的元素即便isNotEmpty,取出的数据元素也或许为null。
长途调用回来方针时,一概要求进行空指针判别,防止NPE。
关于Session中获取的数据,主张进行NPE查看,防止空指针。
级联调用obj.getA().getB().getC();一连串调用,易发生NPE。
正例:运用JDK8的Optional类来防止NPE问题。
12)【引荐】界说时区别unchecked/checked反常,防止直接抛出newRuntimeException(),更不答应抛出Exception或许Throwable,应运用有业务含义的自界说反常。引荐业界已界说过的自界说反常,如:DAOException/ServiceException等。
13)【参阅】关于公司外的http/api敞开接口有必要运用“过错码”;而运用内部引荐反常抛出;跨运用间RPC调用优先考虑运用Result办法,封装isSuccess()办法、“过错码”、“过错简短信息”。
阐明:关于RPC办法回来办法运用Result办法的理由:
运用抛反常回来办法,调用方假如没有捕获到就会发生运转时过错。
假如不加栈信息,仅仅new自界说反常,参加自己的了解的errormessage,关于调用端处理问题的协助不会太多。假如加了栈信息,在频频调用犯错的状况下,数据序列化和传输的功用损耗也是问题。
14)【参阅】防止呈现重复的代码(Don’tRepeatYourself),即DRY准则。
阐明:随意仿制和张贴代码,必定会导致代码的重复,在今后需求修正时,需求修正全部的副本,简略遗失。必要时抽取共性办法,或许抽象公共类,甚至是组件化。
正例:一个类中有多个public办法,都需求进行数行相同的参数校验操作,这个时分请抽取:
privatebooleancheckParam(DTOdto){…}
1
11、日志规约
1)【强制】运用中不行直接运用日志体系(Log4j、Logback)中的API,而应依靠运用日志结构SLF4J中的API,运用门面办法的日志结构,有利于保护和各个类的日志处理办法共同。
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
privatestaticfinalLoggerlogger=LoggerFactory.getLogger(Test.class);
1
2
3
2)【强制】全部日志文件至少保存15天,由于有些反常具备以“周”为频次发生的特色。网络运转状况、安全相关信息、体系监测、管理后台操作、用户灵敏操作需求留存相关的网络日志不少于6个月。
3)【强制】运用中的扩展日志(如打点、临时监控、拜访日志等)命名办法:
appName_logType_logName.log。logType:日志类型,如stats/monitor/access等;logName:日志描绘。这种命名的优点:经过文件名就可知道日志文件归于什么运用,什么类型,什么目的,也有利于归类查找。
阐明:引荐对日志进行分类,如将过错日志和业务日志分隔存放,便于开发人员查看,也便于经过日志对体系进行及时监控。
正例:force-web运用中独自监控时区转化反常,如:force_web_timeZoneConvert.log
4)【强制】在日志输出时,字符串变量之间的拼接运用占位符的办法。
阐明:由于String字符串的拼接会运用StringBuilder的append()办法,有必定的功用损耗。运用占位符仅是替换动作,可以有用进步功用。
正例:logger.debug(“Processingtradewithid:{}andsymbol:{}”,id,symbol);
5)【强制】关于trace/debug/info等级的日志输出,有必要进行日志等级的开关判别。
阐明:尽管在debug(参数)的办法体内榜首行代码isDisabled(Level.DEBUG_INT)为真时(Slf4j的常见完结Log4j和Logback),就直接return,可是参数或许会进行字符串拼接运算。此外,假如debug(getName())这种参数内有getName()办法调用,无谓糟蹋办法调用的开支。
正例:
假如判别为真,那么可以输出trace和debug等级的日志if(logger.isDebugEnabled()){logger.debug(“CurrentIDis:{}andnameis:{}”,id,getName());}
6)【强制】防止重复打印日志,糟蹋磁盘空间,有必要在log4j.xml中设置additivity=false。
正例:
7)【强制】反常信息应该包含两类信息:案发现场信息和反常库房信息。假如不处理,那么经过要害字throws往上抛出。
正例:logger.error(各类参数或许方针toString()+“_”+e.getMessage(),e);
8)【引荐】谨慎地记载日志。出产环境制止输出debug日志;有挑选地输出info日志;假如运用warn来记载刚上线时的业务行为信息,必定要留意日志输出量的问题,防止把服务器磁盘撑爆,并记得及时删去这些调查日志。
阐明:大量地输出无效日志,不利于体系功用进步,也不利于快速定位过错点。记载日志时请考虑:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来优点?
9)【引荐】可以运用warn日志等级来记载用户输入参数过错的状况,防止用户投诉时,莫衷一是。如非必要,请不要在此场景打出error等级,防止频频报警。
阐明:留意日志输出的等级,error等级只记载体系逻辑犯错、反常或许重要的过错信息。
10)【引荐】尽量用英文来描绘日志过错信息,假如日志中的过错信息用英文描绘不清楚的话运用中文描绘即可,不然简略发生歧义。
11)【强制】国际化团队或海外布置的服务器由于字符集问题,运用全英文来注释和描绘日志过错信息。
12、单元测验
1)【强制】好的单元测验有必要恪守AIR准则。
阐明:单元测验在线上运转时,感觉像空气(AIR)相同并不存在,但在测验质量的确保上,却是十分要害的。好的单元测验宏观上来说,具有主动化、独立性、可重复履行的特色。
A:Automatic(主动化)
I:Independent(独立性)
R:Repeatable(可重复)
2)【强制】单元测验应该是全主动履行的,而且非交互式的。测验用例一般是被定时履行的,履行进程有必要彻底主动化才有含义。输出成果需求人工查看的测验不是一个好的单元测验。单元测验中不准运用System.out来进行人肉验证,有必要运用assert来验证。
3)【强制】坚持单元测验的独立性。为了确保单元测验安稳可靠且便于保护,单元测验用例之间决不能互相调用,也不能依靠履行的先后次第。
反例:method2需求依靠method1的履行,将履行成果作为method2的输入。
4)【强制】单元测验是可以重复履行的,不能受到外界环境的影响。
阐明:单元测验一般会被放到持续集成中,每次有代码checkin时单元测验都会被履行。假如单测对外部环境(网络、服务、中心件等)有依靠,简略导致持续集成机制的不行用。
正例:为了不受外界环境影响,要求规划代码时就把SUT的依靠改成注入,在测验时用spring这样的DI结构注入一个本地(内存)完结或许Mock完结。
5)【强制】关于单元测验,要确保测验粒度足够小,有助于准确认位问题。单测粒度至多是类等级,一般是办法等级。
阐明:只要测验粒度小才干在犯错时赶快定位到犯错方位。单测不负责查看跨类或许跨体系的交互逻辑,那是集成测验的领域。
6)【强制】中心业务、中心运用、中心模块的增量代码确保单元测验经过。
阐明:新增代码及时弥补???元测验,假如新增代码影响了原有单元测验,请及时修正。
7)【强制】单元测验代码有必要写在如下工程目录:src/test/java,不答应写在业务代码目录下。
阐明:源码编译时会越过此目录,而单元测验结构默许是扫描此目录。
8)【引荐】单元测验的底子方针:句子掩盖率到达70%;中心模块的句子掩盖率和分支掩盖率都要到达100%
阐明:在工程规约的运用分层中说到的DAO层,Manager层,可重费用高的Service,都应该进行单元测验。
9)【引荐】编写单元测验代码恪守BCDE准则,以确保被测验模块的交给质量。
B:Border,鸿沟值测验,包含循环鸿沟、特别取值、特别时刻点、数据次第等。
C:Correct,正确的输入,并得到预期的成果。
D:Design,与规划文档相结合,来编写单元测验。
E:Error,强制过错信息输入(如:不合法数据、反常流程、业务答应外等),并得到预期的成果。
10)【引荐】关于数据库相关的查询,更新,删去等操作,不能假设数据库里的数据是存在的,或许直接操作数据库把数据刺进进去,请运用程序刺进或许导入数据的办法来准备数据。
反例:删去某一行数据的单元测验,在数据库中,先直接手动添加一行作为删去方针,可是这一行新增数据并不契合业务刺进规矩,导致测验成果反常。
11)【引荐】和数据库相关的单元测验,可以设定主动回滚机制,不给数据库形成脏数据。或许对单元测验发生的数据有明晰的前后缀标识。
正例:在企业智能事业部的内部单元测验中,运用ENTERPRISE_INTELLIGENCE_UNIT_TEST_的前缀来标识单元测验相关代码。
12)【引荐】关于不行测的代码在恰当的机遇做必要的重构,使代码变得可测,防止为了到达测验要求而书写不标准测验代码。
13)【引荐】在规划评审阶段,开发人员需求和测验人员一同确认单元测验规模,单元测验最好掩盖全部测验用例。
14)【引荐】单元测验作为一种质量确保手段,在项目提测前完结单元测验,不主张项目发布后弥补单元测验用例。
15)【参阅】为了更方便地进行单元测验,业务代码应防止以下状况:
结构办法中做的作业过多。
存在过多的全局变量和静态办法。
存在过多的外部依靠。
存在过多的条件句子。
阐明:多层条件句子主张运用卫句子、战略办法、状况办法等办法重构。
16)【参阅】不要对单元测验存在如下误解:
那是测验同学干的作业。本文是开发手册,凡是本文内容都是与开发同学强相关的。
单元测验代码是剩余的。体系的全体功用与各单元部件的测验正常与否是强相关的。
单元测验代码不需求保护。一年半载后,那么单元测验简直处于抛弃状况。
单元测验与线上毛病没有辩证联系。好的单元测验可以最大限度地躲避线上毛病。
13、安全规约
1)【强制】隶归于用户个人的页面或许功用有必要进行权限操控校验。
阐明:防止没有做水平权限校验就可随意拜访、修正、删去别人的数据,比方查看别人的私信内容、修正别人的订单。
2)【强制】用户灵敏数据制止直接展现,有必要对展现数据进行脱敏。
阐明:中国大陆个人手机号码显现为:137****0969,躲藏中心4位,防止隐私泄露。
3)【强制】用户输入的SQL参数严厉运用参数绑定或许METADATA字段值限制,防止SQL注入,制止字符串拼接SQL拜访数据库。
4)【强制】用户恳求传入的任何参数有必要做有用性验证。
阐明:疏忽参数校验或许导致:
pagesize过大导致内存溢出
恶意orderby导致数据库慢查询
任意重定向
SQL注入
反序列化注入
正则输入源串拒绝服务ReDoS
阐明:Java代码用正则来验证客户端的输入,有些正则写法验证一般用户输入没有问题,可是假如进犯人员运用的是特别结构的字符串来验证,有或许导致死循环的成果。
5)【强制】制止向HTML页面输出未经安全过滤或未正确转义的用户数据。
6)【强制】表单、AJAX提交有必要履行CSRF安全验证。
阐明:CSRF(Cross-siterequestforgery)跨站恳求假造是一类常见编程漏洞。关于存在CSRF漏洞的运用/网站,进犯者可以事先结构好URL,只需受害者用户一拜访,后台便在用户不知情的状况下对数据库顶用户参数进行相应修正。
7)【强制】在运用渠道资源,比如短信、邮件、电话、下单、付出,有必要完结正确的防重放的机制,如数量限制、疲惫度操控、验证码校验,防止被滥刷而导致资损。
阐明:如注册时发送验证码到手机,假如没有限制次数和频率,那么可以运用此功用打扰到其它用户,并形成短信渠道资源糟蹋。
8)【引荐】发贴、评论、发送即时消息等用户生成内容的场景有必要完结防刷、文本内容违禁词过滤等风控战略。
14、MySQL数据库
14.1、建表规约
1)【强制】表达是与否概念的字段,有必要运用is_xxx的办法命名,数据类型是unsignedtinyint(1表明是,0表明否)。
阐明:任何字段假如为非负数,有必要是unsigned。
留意:POJO类中的任何布尔类型的变量,都不要加is前缀,所以,需求在设置从is_xxx到Xxx的映射联系。数据库表明是与否的值,运用tinyint类型,坚持is_xxx的命名办法是为了明晰其取值含义与取值规模。
正例:表达逻辑删去的字段名is_deleted,1表明删去,0表明未删去。
2)【强制】表名、字段名有必要运用小写字母或数字,制止呈现数字最初,制止两个下划线中心只呈现数字。数据库字段名的修正价值很大,由于无法进行预发布,所以字段称号需求慎重考虑。
3)阐明:MySQL在Windows下不区别巨细写,但在Linux下默许是区别巨细写。因此,数据库名、表名、字段名,都不答应呈现任何大写字母,防止节外生枝。
正例:aliyun_admin,rdc_config,level3_name
反例:AliyunAdmin,rdcConfig,level_3_name
4)【强制】表名不运用复数名词。
阐明:表名应该仅仅表明表里面的实体内容,不应该表明实体数量,对应于DO类名也是奇数办法,契合表达习惯。
5)【强制】禁用保留字,如desc、range、match、delayed等,请参阅MySQL官方保留字。
6)【强制】主键索引名为pk_字段名;仅有索引名为uk_字段名;一般索引名则为idx_字段名。
阐明:pk_即primarykey;uk_即uniquekey;idx_即index的简称。
7)【强制】小数类型为decimal,制止运用float和double。
阐明:在存储的时分,float和double都存在精度丢失的问题,很或许在比较值的时分,得到不正确的成果。假如存储的数据规模超越decimal的规模,主张将数据拆成整数和小数并分隔存储。
8)【强制】假如存储的字符串长度简直持平,运用char定长字符串类型。
9)【强制】varchar是可变长字符串,不预先分配存储空间,长度不要超越5000,假如存储长度大于此值,界说字段类型为text,独立出来一张表,用主键来对应,防止影响其它字段索引功率。
10)【强制】表必备三字段:id,create_time,update_time。
阐明:其间id必为主键,类型为bigintunsigned、单表时自增、步长为1。create_time,update_time的类型均为datetime类型。
11)【引荐】表的命名最好是遵从“业务称号_表的效果”。
正例:alipay_task/force_project/trade_config
12)【引荐】库名与运用称号尽量共同。
13)【引荐】假如修正字段含义或对字段表明的状况追加时,需求及时更新字段注释。
14)【引荐】字段答应恰当冗余,以进步查询功用,但有必要考虑数据共同。冗余字段应遵从:
不是频频修正的字段。
不是varchar超长字段,更不能是text字段。
不是仅有索引的字段。
正例:商品类目称号运用频率高,字段长度短,称号底子一不变,可在相相关的表中冗余存储类目称号,防止相关查询。
15)【引荐】单表行数超越500万行或许单表容量超越2GB,才引荐进行分库分表。
阐明:假如估计三年后的数据量底子达不到这个等级,请不要在创立表时就分库分表。
16)【参阅】合适的字符存储长度,不光节约数据库表空间、节约索引存储,更重要的是进步检索速度。
正例:如下表,其间无符号值可以防止误存负数,且扩展了表明规模。
方针年纪区间类型字节表明规模
人150岁之内tinyintunsigned1无符号值:0到255
龟数百岁smallintunsigned2无符号值:0到65535
恐龙化石数千万年intunsigned4无符号值:0到约42.9亿
太阳约50亿年bigintunsigned8无符号值:0到约10的19次方
14.2、索引规约
1)【强制】业务上具有仅有特性的字段,即便是多个字段的组合,也有必要建成仅有索引。
阐明:不要以为仅有索引影响了insert速度,这个速度损耗可以疏忽,但进步查找速度是显着的;别的,即便在运用层做了十分完善的校验操控,只需没有仅有索引,依据墨菲规律,必定有脏数据发生。
2)【强制】超越三个表制止join。需求join的字段,数据类型有必要绝对共同;多表相关查询时,确保被相关的字段需求有索引。
阐明:即便双表join也要留意表索引、SQL功用。
3)【强制】在varchar字段上树立索引时,有必要指定索引长度,没必要对全字段树立索引,依据实践文本区别度决议索引长度即可。
阐明:索引的长度与区别度是一对对立体,一般对字符串类型数据,长度为20的索引,区别度会高达90%以上,可以运用count(distinctleft(列名,索引长度))/count(*)的区别度来确认。
4)【强制】页面搜索制止左含糊或许全含糊,假如需求请走搜索引擎来处理。
阐明:索引文件具有B-Tree的最左前缀匹配特性,假如左面的值未确认,那么无法运用此索引。
5)【引荐】假如有orderby的场景,请留意运用索引的有序性。orderby最终的字段是组合索引的一部分,而且放在索引组合次第的最终,防止呈现file_sort的状况,影响查询功用。
正例:wherea=?andb=?orderbyc;索引:a_b_c
反例:索引假如存在规模查询,那么索引有序性无法运用,如:WHEREa>10ORDERBYb;索引a_b无法排序。
6)【引荐】运用掩盖索引来进行查询操作,防止回表。
阐明:假如一本书需求知道第11章是什么标题,会翻开第11章对应的那一页吗?目录浏览一下就好,这个目录便是起到掩盖索引的效果。
正例:可以树立索引的种类分为主键索引、仅有索引、一般索引三种,而掩盖索引仅仅一种查询的一种效果,用explain的成果,extra列会呈现:usingindex。
7)【引荐】运用推迟相关或许子查询优化超多分页场景。
阐明:MySQL并不是越过offset行,而是取offset+N行,然后回来抛弃前offset行,回来N行,那当offset特别大的时分,功率就十分的低下,要么操控回来的总页数,要么对超越特定阈值的页数进行SQL改写。
正例:先快速定位需求获取的id段,然后再相关:
8)SELECTa.*FROM表1a,(selectidfrom表1where条件LIMIT100000,20)bwherea.id=b.id
【引荐】SQL功用优化的方针:至少要到达range等级,要求是ref等级,假如可所以consts最好。
阐明:
consts单表中最多只要一个匹配行(主键或许仅有索引),在优化阶段即可读取到数据。
ref指的是运用一般的索引(normalindex)。
range对索引进行规模检索。
反例:explain表的成果,type=index,索引物理文件全扫描,速度十分慢,这个index等级比较range还低,与全表扫描是小巫见大巫。
9)【引荐】建组合索引的时分,区别度最高的在最左面。
正例:假如wherea=?andb=?,假如a列的简直接近于仅有值,那么只需求单建idx_a索引即可。
阐明:存在非等号和等号混合时,在建索引时,请把等号条件的列前置。如:wherec>?andd=?那么即便c的区别度更高,也有必要把d放在索引的最前列,即索引idx_d_c。
10)【引荐】防止因字段类型不同形成的隐式转化,导致索引失效。
【参阅】创立索引时防止有如下极点误解:
宁滥勿缺。以为一个查询就需求建一个索引。
宁缺勿滥。以为索引会耗费空间、严峻拖慢记载的更新以及行的新增速度。
抵抗专一索引。以为业务的专一性一概需求在运用层经过“先查后插”办法处理。
14.3、SQL句子
1)【强制】不要运用count(列名)或count(常量)来代替count(),count()是SQL92界说的标准计算行数的语法,跟数据库无关,跟NULL和非NULL无关。
阐明:count(*)会计算值为NULL的行,而count(列名)不会计算此列为NULL值的行。
2)【强制】count(distinctcol)核算该列除NULL之外的不重复行数,留意count(distinctcol1,col2)假如其间一列全为NULL,那么即便另一列有不同的值,也回来为0。
3)【强制】当某一列的值满是NULL时,count(col)的回来成果为0,但sum(col)的回来成果为NULL,因此运用sum()时需留意NPE问题。
正例:运用如下办法来防止sum的NPE问题:SELECTIFNULL(SUM(column),0)FROMtable;
4)【强制】运用ISNULL()来判别是否为NULL值。
阐明:NULL与任何值的直接比较都为NULL。
NULL<>NULL的回来成果是NULL,而不是false。
NULL=NULL的回来成果是NULL,而不是true。
NULL<>1的回来成果是NULL,而不是true。
5)【强制】代码中写分页查询逻辑时,若count为0应直接回来,防止履行后面的分页句子。
【强制】不得运用外键与级联,全部外键概念有必要在运用层处理。
阐明:以学生和成绩的联系为例,学生表中的student_id是主键,那么成绩表中的student_id则为外键。假如更新学生表中的student_id,一同触发成绩表中的student_id更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强堵塞,存在数据库更新风暴的危险;外键影响数据库的刺进速度。
6)【强制】制止运用存储进程,存储进程难以调试和扩展,更没有移植性。
7)【强制】数据订正(特别是删去、修正记载操作)时,要先select,防止呈现误删去,确认无误才干履行更新句子。
8)【引荐】in操作能防止则防止,若实在防止不了,需求细心评价in后边的调集元素数量,操控在1000个之内。
9)【参阅】假如有国际化需求,全部的字符存储与表明,均以utf-8编码,留意字符计算函数的区别。
阐明:
SELECTLENGTH(“轻松作业”);回来为12
SELECTCHARACTER_LENGTH(“轻松作业”);回来为4
假如需求存储表情,那么挑选utf8mb4来进行存储,留意它与utf-8编码的区别。
10)【参阅】TRUNCATETABLE比DELETE速度快,且运用的体系和业务日志资源少,但TRUNCATE无业务且不触发trigger,有或许形成事故,故不主张在开发代码中运用此句子。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。