一、命名规范
1、【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例:MAX_STOCK_COUNT
反例:MAX_COUNT
2、【强制】抽象类命名使用Abstract或Base开头;
异常类命名使用Exception结尾;
测试类命名以它要测试的类的名称开始,以Test结尾。
3、【强制】中括号是数组类型的一部分,数组定义如下:String[ ] args;
反例:使用String args[ ] 的方式来定义。
4、【强制】POJO类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型Boolean isDeleted;的属性,它的方法也是isDeleted(),RPC框架在反向解析的时候,
“以为”对应的属性名称是deleted导致属性获取不到,进而抛出异常。
5、【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。
包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
正例: 应用工具类包名为com.alibaba.open.util、类名为MessageUtils(此规则参考spring的框架结构)
6、【参考】各层命名规约: A) Service/DAO层方法命名规约
1) 获取单个对象的方法用get做前缀。
2) 获取多个对象的方法用list做前缀。
3) 获取统计值的方法用count做前缀。
4) 插入的方法用save/insert做前缀。
5) 删除的方法用remove/delete做前缀。
6) 修改的方法用update做前缀。
B) 领域模型命名规约
1) 数据对象:xxxDO,xxx即为数据表名。
2) 数据传输对象:xxxDTO,xxx为业务领域相关的名称。
3) 展示对象:xxxVO,xxx一般为网页名称。
4) POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。
二、常量定义
1、【强制】long或者Long初始赋值时,使用大写的L,不能是小写的l
小写容易跟数字1混淆,造成误解。
说明:Long a = 2l; 写的是数字的21,还是Long型的2?
2、【推荐】不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。
说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。
正例:缓存相关常量放在类CacheConsts下;系统配置相关常量放在类ConfigConsts下。
三、代码格式
1、【强制】大括号的使用约定。
如果是大括号内为空,则简洁地写成{}即可,不需要换行;
如果是非空代码块则: 1) 左大括号前不换行。 2) 左大括号后换行。 3) 右大括号前换行。
4) 右大括号后还有else等代码则不换行;表示终止的右大括号后必须换行。
2、【强制】if / for / while / switch / do 等保留字与括号之间都必须加空格。
3、【强制】任何二目、三目运算符的左右两边都需要加一个空格。 说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
4、【强制】单行字符数限不超过 120 个,超出需要换行时 个,超出需要换行时 遵循如下原则:
1) 第二行相对一缩进 4个空格,从第三行开始不再继续缩进参考示例。
2) 运算符与下文一起换行。
3) 方法调用的点符号与下文一起换行。
4) 方法调用时,多个参数,需要换行时,在逗号后进行。
5) 在括号前不要换行,见反例。
正例:StringBuffer sb = new StringBuffer();
// 超过120个字符的情况下,换行缩进4个空格,点号和方法名称一起换行
sb.append("zi").append("xin")...
.append("huang")...
.append("huang")...
.append("huang");
反例:StringBuffer sb = new StringBuffer();
// 超过120个字符的情况下,不要在括号前换行
sb.append("zi").append("xin")...append
("huang");
// 参数很多的方法调用可能超过120个字符,不要在逗号前换行
method(args1, args2, args3, ...
, argsX);
5、【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。 正例:下例中实参的"a",后边必须要有一个空格。
method("a", "b", "c");
6、【强制】IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用Windows格式。
7、接口过时必须加@Deprecated注解,并清晰地说明采用的新接口或者新服务是什么。
8、【强制】Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。
正例:"test".equals(object);
反例:object.equals("test");
9、【强制】所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较
10、【推荐】所有的局部变量使用基本数据类型。
11、正例:数据库的查询结果可能是null,因为自动拆箱,用基本数据类型接收有NPE风险。
12、【强制】定义DO/DTO/VO等POJO类时,不要设定任何属性默认值。
反例:POJO类的gmtCreate默认值为new Date();但是这个属性在数据提取时并没有置入具体值,
在更新其它字段时又附带更新了此字段,导致创建时间被修改成当前时间。
13、【强制】构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。
14、【推荐】循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展。
四、集合处理
1、【强制】使用集合转数组的方法,必须使用集合的toArray(T[ ] array),传入的是类型完全一样的数组,大小就是list.size()。
说明:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并返回新数组地址;
如果数组元素大于实际所需,下标为 [ list.size() ] 的数组元素将被置为null,其它数组元素保持原值,
因此最好将方法入参数组大小定义与集合元素个数一致。 正例:
List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[ ] array = new String[list.size()];
array = list.toArray(array);
2、【强制】使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,
它的add/remove/clear方法会抛出UnsupportedOperationException异常。
说明:asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法。
Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。
String[] str = new String[] { "you", "wu" }; List list = Arrays.asList(str);
第一种情况:list.add("yangguanbao"); 运行时异常。
第二种情况:str[0] = "gujin"; 那么list.get(0)也会随之修改。
3、使用entrySet遍历Map类集合KV;JDK8,使用Map.foreach方法
4、【参考】利用Set元素唯一的特性,可以快速对一个集合进行去重操作,避免使用List的contains方法进行遍历、对比、去重操作。
五、并发处理
1、【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。 正例:
public class TimerTaskThread extends Thread {
public TimerTaskThread() {
super.setName("TimerTaskThread");
...
}
2、【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程
3、【强制】线程池不允许使用 【强制】线程池不允许使用 Executors去创建,而是通过 去创建,而是通过 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的方式,这样 的处理方式让写同学更加明确线程池运行规则,避资源耗尽风险。 说明: Executors 返回的线程池对象 返回的线程池对象 的弊端 如下 :
1)FixedThreadPool FixedThreadPool 和 SingleThreadPoolPool:
允许的请求队列长度为 Integer.MAX_VALUE,可 能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool :
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
4、【强制】SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。
正例:注意线程安全,使用DateUtils。亦推荐如下处理:
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
说明:如果是JDK8的应用,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,
官方给出的解释:simple beautiful strong immutable thread-safe。
5、【强制】高并发时,同步调用应该去考量锁的性能损耗。
能用无锁数据结构,就不要用锁;
能锁区块,就不要锁整个方法体;
能用对象锁,就不要用类锁。
说明:尽可能使加锁的代码块工作量尽可能的小,避免在锁代码块中调用RPC方法。
6、【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。
说明:线程一需要对表A、B、C依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是A、B、C,否则可能出现死锁。
7、【强制】多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。