IDE的text file encoding设置为UTF-8;IDE中文件的换行符使用Unix格式,不
要使用Windows格式。
接口过时必须加@Deprecated注解,并清晰地说明采用的新接口或者新服务是什
么。
正例:“test”.equals(object); 避免空指针
所有整型包装类对象之间 值 的比较,全部使用equals方法比较。
浮点数之间的 基本数据类型 不能用==来比较,包装数据类型 不能用
equals来判断。
为了防止精度损失,禁止使用构造方法BigDecimal(double)的方式把double值转
化为BigDecimal对象。
正例:优先推荐入参为String的构造方法,或使用BigDecimal的valueOf方法,此方法内部其实执行了
Double的toString,而Double的toString按double的实际能表达的精度对尾数进行了截断。
所有的POJO类属性必须使用包装数据类型。
RPC方法的返回值和参数必须使用包装数据类型。
所有的局部变量使用基本数据类型。
定义DO/DTO/VO等POJO类时,不要设定任何属性默认值。
序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列失败;如果
完全不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值。
构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。
POJO类必须写toString方法。使用IDE中的工具:source> generate toString
时,如果继承了另一个POJO类,注意在前面加一下super.toString。
禁止在POJO类中,同时存在对应属性xxx的isXxx()和getXxx()方法。
慎用Object的clone方法来拷贝对象。
使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一
致、长度为0的空数组。
在使用Collection接口任何实现类的addAll()方法时,都要对输入的集合参数进行
NPE判断。
使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方
法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。
泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用add方
法,而<? superT>不能使用get方法,作为接口调用赋值时易出错。
在无泛型限制定义的集合 赋值给 泛型限制的集合时,在使用集合元素时,需要进行
instanceof判断,避免抛出ClassCastException异常。
不要在foreach循环里进行元素的remove/add操作。remove元素请使用
Iterator方式,如果并发操作,需要对Iterator对象加锁。
在JDK7版本及以上,Comparator实现类要满足如下三个条件,不然Arrays.sort,
Collections.sort会抛IllegalArgumentException异常。
说明:三个条件如下
1)x,y的比较结果和y,x的比较结果相反。
2)x>y,y>z,则x>z。
3)x=y,则x,z比较结果和y,z比较结果相同。
集合初始化时,指定集合初始值大小。如果暂时无法确定初始值大小,请设置为16(即默认值)。
【推荐】使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。
entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。
如果是JDK8,使用Map.forEach方法。
ConcurrentHashMap,K不允许为null,V不允许为null。
并发:
【强制】获取单例对象需要保证线程安全,其中的方法也要保证线程安全。
说明:资源驱动类、工具类、单例工厂类都需要注意。
【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这
样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
【强制】SimpleDateFormat是线程不安全的类,一般不要定义为static变量,
如果定义为static,必须加锁,或者使用DateUtils工具类。
【强制】必须回收自定义的ThreadLocal变量,尤其在线程池场景下,线程经常会被复用,
如果不清理自定义的ThreadLocal变量,可能会影响后续业务逻辑和造成内存泄露等问题。
尽量在代理中使用try-finally块进行回收。
【强制】在使用尝试机制来获取锁的方式中,进入业务代码块之前,必须先判断当前线程是
否持有锁。锁的释放规则与锁的阻塞等待方式相同。
【强制】并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存
加锁,要么在数据库层使用乐观锁,使用version作为更新依据。
说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于
3次。
【强制】多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获
抛出的异常,其它任务便会自动终止运行,如果在处理定时任务时使用
ScheduledExecutorService则没有这个问题。
资金相关的金融敏感信息,使用悲观锁策略。
使用CountDownLatch进行异步转同步操作,每个线程退出前必须调用countDown
方法,线程执行代码注意catch异常,确保countDown方法被执行到,避免主线程无法执行
至await方法,直到超时才返回结果。
说明:注意,子线程抛出异常堆栈,不能在主线程try-catch到。
避免Random实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一
seed导致的性能下降。
说明:Random实例包括java.util.Random 的实例或者Math.random()的方式。
正例:在JDK7之后,可以直接使用API ThreadLocalRandom,而在程持有一个实例。
volatile解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题,但
是如果多写,同样无法解决线程安全问题。count++操作,如果是JDK8,推荐使用LongAdder对象,比AtomicLong性能更好(减少乐观
锁的重试次数)。
HashMap在容量不够进行resize时由于高并发可能出现死链,导致CPU飙升,在
开发过程中可以使用其它数据结构或加锁来规避此风险。
ThreadLocal对象使用static修饰,ThreadLocal无法解决共享对象的更新问题。
控制语句:
【强制】当switch括号内的变量类型为String并且此变量为外部参数时,必须先进行null
判断。
【强制】在高并发场景中,避免使用”等于”判断作为中断或退出的条件。
不要在其它表达式(尤其是条件表达式)中,插入赋值语句。
将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
【推荐】接口入参保护,这种场景常见的是用作批量操作的接口。
【参考】下列情形,需要进行参数校验:
1)调用频次低的方法。
2)执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参数错误导致
中间执行回退,或者错误,那得不偿失。
3)需要极高稳定性和可用性的方法。
4)对外提供的开放接口,不管是RPC/API/HTTP接口。
5)敏感权限入口。
注释:
【强制】类、类属性、类方法的注释必须使用Javadoc规范,使用/*内容/格式
【强制】所有的抽象方法(包括接口中的方法)必须要用Javadoc注释、除了返回值、参数、
异常说明外,还必须指出该方法做什么事情,实现什么功能。
说明:对子类的实现要求,或者调用注意事项,请一并说明。
【强制】所有的类都必须添加创建者和创建日期。