阿里Java开发手册

时间:2021-04-26 16:50:10

1.1 命名风格

(1)常量命名全部大写,单词间用下划线隔开。

(2)抽象类命名以Abstract或Base开头;异常类命名以Exception结尾;测试类命名以它要测试的类名开始,以Test结尾。

(3)类型与中括号之间无空格定义数组(例:String[] args)。

(4)Boolean类型的变量不要加is前缀(例:Boolean isDeleted,它的方法名称也是isDeleted(),会造成部分框架解析失败)。

(5)包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词(例:com.pajk.util),统一使用单数形式。

(6)接口类中的方法和属性不要加任何修饰符(public也不要加,例:void commit()),尽量不要在接口里定义变量,如果一定要定义,必须是与接口方法相关的,并且是整个应用的基础常量。

(7)枚举类成员名称需要全部大写,单词间用下划线隔开(枚举就是特殊的常量类,且构造方法被默认强制为私有)。

1.2 常量定义

(1)不允许任何魔法值(即没有预先定义的常量)出现在代码中(例:String key = "pajk")。

(2)long或者Long初始化时,使用大写的L,因为小写的容易跟数字1混淆。

1.3 代码格式

(1)相同参数类型,相同业务含义,才可以使用可变参数。

1.4 OOP规约

(1)不能使用过时的类或方法,过时的接口必须加@Deprecated注解,并清晰的说明新接口是什么。

(2)Object的equals方法容易抛NPE异常,JDK7建议使用java.util.Objects#equlas方法。

(3)所有包装类型对象之间的比较,全部使用equals方法,不要用==判断。

(4)POJO类属性必须使用包装数据类型,RPC方法的返回值和参数必须使用包装数据类型(防止NPE异常),所有的局部变量使用基本数据类型。

(5)在定义DO/DTO/VO等POJO类时,不要设定任何属性默认值。

(6)POJO类必须写toString方法。IDE中工具 source-generate toString时,如果继承了另一个POJO类,注意在前面加一下super.toString。

(7)类内推荐的方法定义顺序:public > private > getter / setter 方法。

(8)getter / setter 方法中不要增加业务逻辑,否则会增加排查问题的难度。

(9)对象的clone方法是浅拷贝,若想实现深拷贝,需要重写clone方法来实现属性对象的拷贝。

(10)对任何类、方法、参数和变量,严控访问范围,过于宽泛的访问范围,不利于模块解耦(例:如果是一个private方法,想删除很简单,public则要考虑很多东西)。

1.5 集合处理

(1)只要重写equlas,就必须重写hashCode。

(2)String重写了hashCode和equals,所以很方便用来作为Map的key使用。

(3)subList返回的是ArrayList的内部类,只是ArrayList的一个视图,并不能转为ArrayList。

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

(5)数组转集合的方法为Arrays.asList,体现的是适配器模式,后台的数据结构仍是数组,所以用该方法转换后的集合不能修改内部元素。

(6)remove集合元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

(7)HashMap的key和value可以为空,ConcurrentHashMap则不行。

(8)有序性(遍历的结果是按某种比较规则排列的)和稳定性(每次遍历的元素次序是一定的)的比较:ArrayList是order/unsort,HashMap是unorder/unsort,TreeSet是order/sort。

1.6 并发处理

(1)获取单例对象需要保证线程安全,其中的方法也要保证线程安全。

(2)线程资源必须通过线程池提供。

(3)线程池不允许使用Executors创建,而是通过ThreadPoolExecutor的方式创建。

(4)SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。

(5)如果是JDK8,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat。

(6)高并发场景中,同步调用要考虑锁对性能的损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

(7)如果线程一需要对A、B、C依次全部加锁后才可以进行更新操作,那么线程而的加锁顺序也必须是A、B、C,否则可能出现死锁。

(8)要么在应用层加锁,要么在缓存层加锁,要么在数据库层使用乐观锁。如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。

1.7 控制语句

(1)在一个swtich块内,都必须包含一个default语句并且放在最后,即使它什么代码也没有。

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

(3)为了日后方便维护代码,if-else应避免使用,就算使用,请勿超过3层,超过的话可以使用卫语句来代替(卫语句:就是把复杂的条件表达式拆分成多个条件表达式为真时,立刻从方法体返回给调用方,例:if(isBusy()))