阿里巴巴代码规范

目录

编码规约

异常日志

安全规约

MySQL数据库

相关资料:


编码规约

(一)命名风格:

1杜绝完全不规范的缩写,严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。

2、代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。

3、类名使用 大驼峰风格,但以下情形例外:DO / BO / DTO / VO / AO / PO 等。

4、方法名、参数名、成员变量、局部变量都统一使用 小驼峰 风格。

5、常量命名全部大写,单词间用下划线隔开,名字长点不要紧,一定要做到意思清楚明白。

6、包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用 单数形式,但是类名如果有复数含义,类名可以使用复数形式。

7代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。

8类型与中括号紧挨相连来定义数组。例:int[] arrayDemo;

9抽象类命名使用AbstractBase开头;异常类命名使用Exception结尾;测试类命名以它要测试的类名开始,以Test结尾。

(二)常量定义:

1不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。

反例:String key = "Id#taobao_"+tradeId;

2、给Long类型变量初始化赋值时要使用大写的L,不能是小写的 l,小写的 l 容易跟数字1混淆,降低可读性。

3不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。

4常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。

(三)代码格式:

1大括号的使用约定

如果是大括号内为空,则简洁地写成{}即可,不需要换行如果是非空代码块需要满足以下规则 

         1左大括号前不换行。

2左大括号后换行。

3右大括号前换行

4右大括号后还有else等代码则不换行表示终止的右大括号后必须换行。

7方法参数在定义和传入时,多个参数逗号后边必须加空格。

     例:下例中实参的"a",后边必须要有一个空格。

               method("a", "b", "c");

8IDEtext file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用Windows格式。

9不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。

(四)OOP规约:

1避免通过一个类的对象引用访问此类的静态变量或静态方法,直接用类名来访问即可。(通过类的对象调用静态变量或方法的话会增加编译成本)

2所有的覆写方法,必须加@Override注解。

3外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated注解,并清晰地说明采用的新接口或者新服务是什么。

4不能使用过时的类或方法。

5Objectequals方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals

 正例:"test".equals(object);

 反例:object.equals("test"); 

6所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较。

7关于基本数据类型与包装数据类型的使用标准如下:

【强制】所有的POJO类属性必须使用包装数据类型。

【强制】RPC方法的返回值和参数必须使用包装数据类型。

说明:数据库的查询结果可能是 null,因为自动拆箱,用基本数据类型接收有 NPE 风险。

【推荐】所有的局部变量使用基本数据类型。

8POJO类必须写toString方法。使用IDE中的工具:source> generate toString 时,如果继承了另一个POJO类,注意在前面加一下super.toString

9构造方法里面禁止加入任何业务逻辑。

10循环体内,字符串的连接方式,使用StringBuilderappend方法进行扩展。(对照String

11final可以声明类、成员变量、方法、以及本地变量,下列情况使用final关键字:

1不允许被继承的类,如:String类。

2不允许修改引用的域对象,如:POJO类的域变量。

3不允许被重写的方法,如:POJO类的setter方法。

4不允许运行过程中重新赋值的局部变量。

5避免上下文重复使用一个变量,使用final描述可以强制重新定义一个变量,方便更好地进行重构。

(五)集合处理

1关于hashCodeequals的处理,遵循如下规则:

1因为Set存储的是不重复的对象,依据hashCodeequals进行判断,所以Set存储的对象必须重写这两个方法。

2如果自定义对象作为Map的键,那么必须重写hashCodeequals

2 ArrayListsubList结果不可强转成ArrayList,否则会抛出ClassCastException (类型转换异常)异常

3subList场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均会产生ConcurrentModificationException 异常。

4使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()

5使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。

6不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator 方式。

(六)控制语句

1在一个switch块内,每个case要么通过break/return等来终止,要么注释说明程序将继续执行到哪一个case为止;在一个switch块内,都必须包含一个default语句并且放在最后,即使空代码。

2if/else/for/while/do语句中必须使用大括号。即使只有一行代码,避免采用单行的编码方式:if (condition) statements;

3在高并发场景中,避免使用等于判断作为中断或退出的条件。如果并发控制没有处理好,容易产生等值判断被击穿的情况,使用大于或小于的区间判断条件来代替。

4、尽量不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。

5避免采用取反逻辑运算符。取反逻辑不利于快速理解,并且取反逻辑写法必然存在对应的正向逻辑写法。

(七)注释规约

1类、类属性、类方法的注释必须使用Javadoc规范,使用/**内容*/格式,不得使用// xxx方式。

示例:

类(types)注释模板:
/**   
 * @ClassName:  ${type_name}   
 * @Description:${todo}  
 * @author: ******
 * @date:   ${date} ${time}    
 */
方法(method)注释模板:
/** 
* @MethodName: ${enclosing_method} 
* @Description: ${todo}
* @param ${tags}
* @return ${return_type}
* @throws
* @date ${date} ${time}
* @author ******
*/

2所有的抽象方法(包括接口中的方法)必须要用Javadoc注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。

3所有的类都必须添加创建者和创建日期。

4方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。

5与其半吊子英文来注释,不如用中文注释把问题说清楚。专有名词与关键字保持英文原文即可。

6代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。

7谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。

8好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。

(八)其它

1在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。

2注意 Math.random() 这个方法返回是double类型,注意取值的范围 0≤x<1(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将x放大10的若干倍然后取整,直接使用Random对象的nextInt或者nextLong方法。

3不要在视图模板中加入任何复杂的逻辑。

4任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存。

5及时清理不再使用的代码段或配置信息。


异常日志

(一)异常处理

1异常不要用来做流程控制,条件控制。

2catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。

3捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。

4try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务。

5不要在finally块中使用return

6捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。

7、注意防止空指针异常。 

8避免出现重复的代码(Don’t Repeat Yourself),即DRY原则。随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是组件化。

(二)日志规约

1日志文件推荐至少保存15天,因为有些异常具备以为频次发生的特点。

2避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity=false

3异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throws往上抛出。

4谨慎地记录日志。生产环境禁止输出debug日志;有选择地输出info日志;如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。

5可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。


安全规约

1隶属于用户个人的页面或者功能必须进行权限控制校验

说明:防止没有做水平权限校验就可随意访问、修改、删除别人的数据,比如查看他人的私信内容、修改他人的订单。

2用户敏感数据禁止直接展示,必须对展示数据进行脱敏。

说明:个人手机号码显示为:158****9119,隐藏中间4位,防止隐私泄露。

3用户请求传入的任何参数必须做有效性验证。

4禁止向HTML页面输出未经安全过滤或未正确转义的用户数据。

5表单、AJAX提交必须执行CSRF安全过滤。CSRF跨站域伪造请求)

6在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放限制,如数量限制、疲劳度控制、验证码校验,避免被滥刷导致资损。

说明:如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其它用户,并造成短信平台资源浪费。

7发贴、评论、发送即时消息等用户生成内容的场景必须实现防刷、文本内容违禁词过滤等风控策略。


MySQL数据库

(一)建表规约

1表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是unsigned tinyint 1表示是,0表示否)。

说明: unsigned tinyint类型只能存储0255的整数,不能存储负数,tinyint的范围是-128127的整数。

正例:表达逻辑删除的字段名is_deleted1 表示删除,0 表示未删除。

2表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。

说明:MySQL Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、表名、字段名,都不允许出现任何大写字母,避免节外生枝。

3表名不使用复数名词。

说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量

4禁用保留字,如descrangematchdelayed等。

5主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。

说明:pk_ primary keyuk_ unique keyidx_ index的简称。

6小数类型为decimal,禁止使用floatdouble

说明:floatdouble在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过decimal的范围,建议将数据拆成整数和小数分开存储。

7如果存储的字符串长度几乎相等,使用char定长字符串类型。

8 varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。

9表必备三字段:id, gmt_create, gmt_modified

说明:其中id必为主键,类型为unsigned bigint、单表时自增、步长为 1gmt_create, gmt_modified的类型均为datetime类型,前者表示创建时间,后者表示更新时间。

10表的命名最好是加上业务名称_表的作用

11库名与应用名称尽量一致。

12如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。

二)SQL语句

1不要使用count(列名)count(常量)来替代count(*)count(*)SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。

说明:count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的行。

2count(distinct col) 计算该列除NULL之外的不重复行数,注意 count(distinct col1, col2) 如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0

3当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为NULL,因此使用sum()时需注意NPE问题。

正例:可以使用如下方式来避免sumNPE问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;

4使用ISNULL()来判断是否为NULL值。

5在代码中写分页查询逻辑时,若count0应直接返回,避免执行后面的分页语句。

6数据订正(特别是删除、修改记录操作)时,要先select,避免出现误删除,确认无误才能执行更新语句。

7 in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控制在1000个之内。

8 TRUNCATE TABLE DELETE 速度快,且使用的系统和事务日志资源少,但TRUNCATE 无事务且不触发trigger,有可能造成事故,故不建议在开发代码中使用此语句。

(三)ORM映射

1在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。

说明:1)增加查询分析器解析成本。2)增减字段容易与resultMap配置不一致。

2 POJO类的布尔属性不能加is,而数据库字段必须加is_,要求在resultMap中进行字段与属性之间的映射。

说明:参见定义POJO类以及数据库字段定义规定,在<resultMap>中增加映射,是必须的。在MyBatis Generator生成的代码中,需要进行对应的修改。

3不要用resultClass当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义;反过来,每一个表也必然有一个与之对应。

4 sql.xml配置参数使用:#{}#param# 不要使用${} 此种方式容易出现SQL注入。

5 iBATIS自带的queryForList(String statementName,int start,int size)不推荐使用。

说明:其实现方式是在数据库取到statementName对应的SQL语句的所有记录,再通过subList start,size的子集合。

正例:Map<String, Object> map = new HashMap<String, Object>();    map.put("start", start);    map.put("size", size);

6不允许直接拿HashMapHashtable作为查询结果集的输出。

说明:resultClass=”Hashtable”,会置入字段名和属性值,但是值的类型不可控。

7更新数据表记录时,必须同时更新记录对应的gmt_modified字段值为当前时间。

8 @Transactional事务不要滥用。事务会影响数据库的QPS(每秒查询率),另外使用事务的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。


相关资料:

https://www.jianshu.com/p/bc8fed863eca   白话阿里巴巴Java开发手册(编程规约)

https://www.jianshu.com/p/5b6d180bd1c2 白话阿里巴巴Java开发手册(异常日志)

https://www.jianshu.com/p/9528c4ea1504  白话阿里巴巴Java开发手册(安全规约)

https://github.com/alibaba/p3c/blob/master/eclipse-plugin/README_cn.md 阿里巴巴 Java 开发规约插件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值