阿里巴巴JAVA开发手册

开发手册

1、编程规范

(一)命名规范

类型 规范
命名 不能以_$开头或结尾,正确英文拼写和语法,避免不规范缩写
类名 UpperCamelCase风格(领域模式除外,DO、BO、DTO、VO)
方法 参数 变量名 lowerCamelCase风格
常量 全大写,以_隔开,语义表达完整,不要嫌长
抽象类名 以Abstract或Base开头
异常类名 以Exception结尾
测试类名 以Test结尾
常量类 以Consts结尾
数组 数组定义以下:String[] args
布尔变量 不能加is
包名 小写,一个天然语义单词,单数形式
设计模式 在类名中体现出具体模式
接口 字段和方法不加任何修饰符,以形容能力的接口名称,取形容词为接口名(一般-able形式)
接口实现类 以Impl结尾
枚举类 以Enum结尾,枚举成员全大写,以_隔开(枚举就是特殊的常量类,且构造方法被默认强制私有)

各层命名规范java

Service/DAO层方法命名规范 1 获取单个对象的方法用 get 作前缀
2 获取多个对象的方法用 list 作前缀
3 获取统计值的方法用 count 作前缀
4 插入的方法用 save(推荐)或 insert 作前缀
5 删除的方法用 remove(推荐)或 delete 作前缀
6 修改的方法用 update 作前缀
领域模型命名规范 1 数据对象:xxxDO,xxx为数据表名
2 数据传输对象:xxxDTO,xxx为业务领域相关的名称
3 展现对象:xxxVO,xxx通常为网页名称
4 POJODO/DTO/BO/VO的统称,禁止命名为xxxPOJO

(二)常量定义

类型 规范
常量 不容许魔法值(未定义常量)直接出如今代码中
长整型 初始化用L(大写)结尾,避免l(小写)与数字1混淆
常量类 按功能进行分类,分开维护
复用层次 1 跨应用共享常量
2 应用内共享常量
3 子工程内共享常量
4 包内共享常量
5 类内共享常量
Enum类 若是变量在范围内变化用Enum,若是还带有名称以外的延伸属性,必须用Enum类,如MONDAY(1)

(三)格式规约

类型 规范
大括号的使用 1 空代码块 简洁地写成{},不须要换行
2 非空代码块:左大括号前不换行,后换行;
右大括号前换行,后换行(还有else则不换行,表示终止必须换行)
括号的使用 左括号与后一个字符之间不出现空格,右括号与前一个字符之间也不能出现空格
关键字 if/for/while/switch/do 等保留字与左右括号之间都必须加空格
运算符 任何运算符左右都必须加一个空格
缩进 缩进采用4个空格,禁止使用tab字符
例: 图片描述
单行字符 单行字符数限制不能超过120个,超出须要换行,遵循原则以下:
1 第二行相对第一行缩进4字符,第三行开始,相对第二行再也不缩进;
2 运算符与下文一块儿换行
3 方法调用.符号与下文一块儿换行
4 多个参数超行,逗号后进行换行
5 在括号前不要换行
方法参数 方法参数在定义和传入时,多个参数逗号后边必须加空格
编码和换行符 IDE的text file encoding设置为utf-8,IDE文件换行符使用Unix格式,而非windows格式
字符对齐 没有必要增长若干空格来使某一行的字符与上一行的相对字符对齐
方法体 方法体内的执行语句组、变量的定义语句组、不一样的业务逻辑之间或者不一样的语义之间插入一个空行(没有必要插入多行)。相同业务逻辑和语义之间bu须要插入空行

(四)OOP规约

类型 规范
静态成员访问 直接使用类名访问,避免经过对象引用访问,无谓增长编译器解析成本。
覆写方法 全部覆写方法,必须添加@Override注解(准确判断是否覆盖成功)
可变参数编程 相同参数类型,相同业务含义,才可以使用Java的可变参数,避免使用Object,可变参数必须放置在参数列表的最后
对外暴露的接口签名 原则上不容许修改方法签名,避免对接口调用方产生影响,接口过期必须添加@Deprecated注解,并清晰第说明采用的新接口或者新服务是什么
过期的类或方法 不能调用过期的类或方法,做为调用方,有义务去考证过期方法的新实现是什么
equals方法 应使用常量或确保有值的对象来调用equals,避免空指针异常
包装类比较 全部的相同类型的包装类之间值的比较,所有使用equals方法比较,
缘由:Integer在-128 至127之间的赋值,Integer对象在IntegerCache.cache产生,会复用已有对象,而在这个区间以外,都会在堆上产生。
例子:Integer a = 111;Integer b = 111; a == b为true;
Integer a = 1111;Integer b = 1111;a == b为false
基本数据类型
包装数据类型使用标准
1 全部的POJO类属性必须使用包装数据类型
2 RPC方法的返回值和参数必须使用包装数据类型
3全部的局部变量【推荐】使用基本数据类型。
说明:POJO类无初值提醒使用者显式赋值,任何NPE问题,入库检查,都由使用者保证。
POJO类 定义DO/DTO/VO等POJO类时,不要设定任何属性默认值
serialVersionUID 序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列化失败;
若是彻底不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值
构造方法 构造方法里面禁止写入任何业务逻辑,若是有初始化逻辑,请放在init方法中
toString方法 POJO类必须写toString方法,使用IDE中的工具,source>generate toString时,若是继承了另外一个POJO类,注意在前面加一下super.toString()(即同时输出父类的信息,在发放抛出异常时,经过toString()方法打印其属性值,便于排查问题)。
也可以使用apache common工具类库的ReflectionToStringBuilder.toString(this)经过反射打印出类中的属性,包括父类的属性。
String的split方法 使用索引访问String的split方法获得的数组时,需作最后一个分隔符后有无内容的检查,不然会有抛IndexOutOfBoundsException的风险;例:"a,b,c,,";
同名方法 当一个类中有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一块儿,便于阅读。
类内方法定义顺序 公有或保护方法 > 私有方法 > getter/setter方法。
getter/setter方法 setter方法中,参数名称与类成员名称一致,this.成员名=参数名,在getter/setter方法中,尽可能不要增长业务逻辑,增长排查问题的难度。
字符串联接 在循环体内,字符串的联接方式,使用StringBuilder的append方法进行扩展。反编译出的字节码文件显示每次循环都会new一个StringBuilder对象,进行append操做,并调用toString方法返回String对象,形成内存资源浪费。
final关键字 final可提升程序响应效率,声明成final的状况:
1 不须要从新赋值的变量,包括类属性、局部变量。
2 对象参数前加final,表示不容许修改引用的指向。 3 类方法肯定不容许被重写。
clone方法 慎用Object的clone方法来拷贝对象,默认是浅拷贝,共享对象属性引用,若想实现深拷贝需重写clone方法实现属性对象的拷贝。
类成员与方法访问控制从严 1 不容许外部直接new建立对象,构造方法必须是private
2 工具类不容许有public 或 default构造方法
3 类非static成员变量而且与子类共享,必须是protected
4 类非static成员变量而且仅在本类使用,必须是private
5 类static成语言变量而且仅在本类使用,必须是privat
6 如果static成员变量,必须考虑是否为final
7 类成员方法只供类内部调用,必须是private
8 类成员方法只对继承类公开,那么限制为protected

(五)集合处理

类型 规范
hashCode和equals 1 只要重写equals,必须重写hashCode[equals 结果相同,hashCode必须一致;hashCode相同,equals不必定相同]
2 Set存储的是不可重复的对象,依据hashCOde和equals进行判断,因此Set存储的对象必须重写方法
3 若是自定义对象做为Map的键,那么必须重写hashCode和equals
ArrayList的subList subList结果不可强转为ArrayList,不然会抛出ClassCastException异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList;
说明:subList返回的是ArrayList的内部类SubList,并非ArrayList,而是ArrayList的一个视图,对于SubList子列表的全部操做最终会反映到原列表上。
subList场景 在subList场景中,高度注意对原集合元素个数的修改,会致使子列表的遍历、增长、删除均产生ConcurrentModificationException异常。
集合转数组 必须使用集合的toArray(T[] a),传入的是类型彻底同样的数组,大小就是list.size();
说明:调用toArray代餐方法,a.length小于集合size时,从新分配内存空间,返回新数组地址(长度为集合size),a.length大于集合size时,设置[list.size()]的数组元素为null,其余数组元素保持原值,所以最好a长度与集合元素个数一致。
Arrays.asList() 使用工具类Arrays.asList()把数组转换成集合时,没法调用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。
说明:asList的返回对象是一个Arrays内部类,并无实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据还是数组。
泛型通配符<? extends T> 泛型上限,用来接受返回的数据,此写法的泛型集合不能使用add方法。
foreache循环 集合foreach底层是迭代器模式,在foreach循环中进行元素的remove/add操做可能会抛出异常,remove元素请使用Iterator方式,若是并发操做,须要对Iterator对象加锁。
Comparator JDK7版本以上,Comparator要知足自反性,传递性,对称性,否则Arrays.sort,Collections.sort会报IllegalArgumentException异常。
集合初始化 集合初始化时,尽可能指定集合初始值大小。
键值对集合遍历 使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。
说明:keySet实际上是遍历了2次,一次是转为Iterator对象,另外一次是从hashMap中取出key所对应的value,而entrySet只遍历一次就把k,v都放到entry中,效率更高,若是是JDK8,使用Map.foreach方法。
Map类存储null值 图片描述
说明:不容许null值时,存储null值会抛出NPE异常。
集合的有序性和稳定性 合理利用好集合的有序性(sort)和稳定性(order),皮面集合的无序性(unsort)何不稳定性(unorder)带来的负面影响。
说明:稳定性指集合每次遍历的元素次序是必定的。有序性是指遍历的结果是按某种比较规则依次排序的。如:Array是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort;
Set特性 利用Set元素惟一的特性,能够快速对一个集合进行去重操做,避免使用List的contains方法进行遍历、对比、去重操做。

并发处理

类型 规范
获取单例对象 须要保证线程安全,其中非方法也要保证线程安全
说明:资源驱动类、工具类、单例工厂类都须要注意。
建立线程或线程池 建立线程或线程池时请指定有意义的线程名称,方便出错时回溯。
线程资源 线程资源必须经过线程池提供,不容许在应用中自行显式建立线程。
说明:使用线程池的好处是减小在建立和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。避免形成系统建立大量同类线程而致使消耗完内存或“过分切换”问题。
线程池建立 不容许使用Executors建立,而是经过ThreadPoolExecutor的方式,明确线程池的运行规则,规避资源耗尽的风险。
说明:FixedThreadPool 和SingleThreadPool 容许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量请求,从而致使OOM。 CachedThreadPool 和ScheduledThreadPool容许的建立线程数量为Integer.MAX_VALUE,可能会建立大量的线程,从而致使OOM。
SimpleDateFormat 是线程不安全的类,通常不要定义为static变量,若是定义为static,必须加锁,或者使用DateUtils工具类,亦推荐使用ThreadLocal。
说明:若是是JDK8,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFirmatter。
高并发 高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。
并发修改 并发修改同一记录时,避免更新丢失,要么在应用层加锁,要么在缓存加锁,要么在数据层使用乐观锁,使用version做为更新依据。
说明:若是每次访问冲突几率小于20%,推荐使用乐观锁,不然使用悲观锁。乐观锁的重试次数不能小于3次。
定时任务 多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其余任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。
CountDownLatch 使用CountDownLatch进行异步转同步操做,每一个线程退出前必须调用countDown方法,线程执行代码注意catch异常,确保countDown方法能够执行,避免主线程没法执行至countDown方法,直到超时才返回结果。
说明:注意,子线程抛出异常堆栈,不能在主线程try-catch到。
Rondom 避免Random实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed致使性能降低。
说明:Random实例包括java.util.Random和Math.random()实例。 在JDK7以后,能够直接使用API ThreadLocalRandom,在JDK7以前,能够作到每一个线程一个实例。
双重检查 经过双重检查锁(double-checked locking)(在并发场景)实现延迟初始化的优化问题隐患,推荐问题解决方案中较为简单一种(JDK5以后),将目标属性声明为volatile型。
volatile volatile解决多线程内存不可见问题。对于一写多读,是能够解决变量同步问题,可是若是多写,一样没法解决线程安全问题.若是是i++操做,经过AtomicInteger.addAndGet(1);若是是JDK8,推荐使用LongAdder对象,比AtomicLong性能更好(减小乐观锁的重试次数)。
HashMap HashMap在容量不够进行resize时因为高并发可能出现死链,致使CPU飙升,在开发过程当中注意规避此风险。
ThreadLocal ThreadLocal没法解决共享对象的更新问题,ThreadLocal对象建议使用static修饰,这个变量是针对一个线程内全部操做共有的,因此设置为静态变量,全部此类实例共享此静态变量,也就是说类第一次被使用时装载,只分配一块存储空间,全部此类的对象(同一线程内)均可以操做这个变量。

控制语句

类型 规范
switch 在switch块中,每一个case要么经过break/return等来终止,要么注释说明程序将继续执行到哪个case为止;在一个switch块内,都必须包含一个default语句而且放在最后,即便什么代码也没有。
if/else/for/while/do 在if/else/for/while/do语句中必须使用大括号,即便只有一行代码
else 推荐尽可能少用else,if-else 可改写为 if() { return} //接着写else业务逻辑
说明:若是非得使用if..else if..else,勿超过3层,超过请使用卫语句,或者状态模式来实现。
条件判断语句 不要在条件判断中执行复杂语句,将复杂语句的结果赋值给一个有意义的布尔变量名,以提升可读性。
循环体 循环体重的语句要考量性能,如下操做尽可能移至循环体外处理,定义对象、变量、获取数据库链接,进行没必要要的try-catch操做(这个try-catch是否能够移至循环体外)
接口入参保护 对接口接受参数进行检验,避免错误不合理的参数,这种场景常见的是用于作批量操做的接口。
参数校验 场景:1 调用频次低的方法。
2 执行时间开销大,参数校验时间几乎能够忽略不计,但由于参数错误致使中间执行回退或者错误,得不偿失。
3 须要极高稳定性和可用性的方法。
4 对外提供的开发接口,无论是RPC/API/HTTP接口。
敏感权限入口。
不须要参数校验 场景:1 既有可能被循环调用的方法,不建议对参数进行校验。但在方法说明里面必须注明外部参数检查。
2 底层方法调用频度都比较高,通常不校验。
3 被声明成private只会被本身代码调用的方法时,可以确认调用方法的传入参数作过检查或确定不会有问题,此时能够不校验参数。

注释规约

类型 规范
类、类属性、类方法 注释必须使用Javadoc规范,/* /,不得使用//xxx
抽象方法(接口方法) 必需要用Javadoc注释,除了返回值、参数、异常说明外,还必须指出该方法作什么事情,实现什么功能。
对子类的实现要求,或者调用注意事项,请一并说明。
全部的类都必须添加建立者信息。
方法内部注释 方法内部单行注释在被注释语句上方另起一行,使用//注释。方法内部多行注释 使用/ /注释,注意与代码对齐。
枚举字段 全部枚举类型字段必需要有注释,说明每一个数据项的用途。
英文注释 英文水平很差,不如用中文注释把问题说清楚,专有名词与关键字保持英文原文。
代码修改 代码修改的同时,注释也要进行相应的修改,尤为是参数、返回值、异常、核心逻辑等的修改。
注释掉的代码 尽可能配合说明,而不是简单的注释掉
说明:代码被注释有两种可能,1后续恢复此段代码逻辑 2永久不用 前者若是不备注信息,难以知晓注释动机,后者建议直接删掉(代码仓库保存历史代码)
注释要求 1、准确反应设计思想和代码逻辑;2、描述业务含义,使阅读者能迅速了解代码背后信息。能够帮助本身后期理解当时思路;也可给继任者快速接替本身工做。
有效注释 好的命名、代码结构是自解释的,注释力求精简准确、表达到尾。避免滥用。
特殊注释标记 1 TODO(待办事宜):(标记人、标记时间、[预计处理时间])
2 FIXME(错误,不能工做):(标记人、标记时间、[预计处理时间])

其余

类型 规范
正则表达式 利用好其预编译功能,能够有效加快正则匹配速度
不要再方法体内定义: Pattern pattern = Pattern.compile(规则);
velocity velocity调用POJO类的属性时,建议直接使用属性名取值便可,模板引擎会自动按规范调用POJO的getxxx(),若是是boolean基本数据类型变量(boolean命名不须要加is前缀),会自动调用isxxx(),若是是Boolean包装类对象,优先调用getxxx()。
页面变量 若是后台输送给页面的变量必须加$!{var} 中间的感叹号,若是var==null或不存在,那么${var}会直接显示在页面上
相关文章
相关标签/搜索