阿里巴巴Java开发手册——摘录

来源:互联网 发布:冰与火战歌网络异常 编辑:程序博客网 时间:2024/06/06 07:38

(一)命名规约

8.【强制】POJO类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。

反例:定义为基本数据类型boolean isSuccess;它的方法也是isSuccess(),RPC框架在反向解析的时候“以为”对应的属性名称是success,导致属性获取不到,进而抛出异常。

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

正例:应用工具类包名为com.alibaba.open.util、类名为MessageUtils(此规则参考spring的框架结构)

(二)常量定义

3.【推荐】不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。

如:缓存相关的常量放在类:CacheConsts下;系统配置相关的常量放在类:ConfigConsts下。说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。

(三)格式规约

8.【强制】IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用windows格式。

(四) OOP规约

7.【强制】所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较。

说明:对于Integer var=?在-128至127之间的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用equals方法进行判断。

8.【强制】关于基本数据类型与包装数据类型的使用标准如下:

1)所有的POJO类属性必须使用包装数据类型。

2)RPC方法的返回值和参数必须使用包装数据类型。

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

说明:POJO类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何NPE问题,或者入库检查,都由使用者来保证。

正例:数据库的查询结果可能是null,因为自动拆箱,用基本数据类型接收有NPE风险。反例:比如显示成交总额涨跌情况,即正负x%,x为基本数据类型,调用的RPC服务,调用不成功时,返回的是默认值,页面显示:0%,这是不合理的,应该显示成中划线-。所以包装数据类型的null值,能够表示额外的信息,如:远程调用失败,异常退出。

9.【强制】定义DO/DTO/VO等POJO类时,不要设定任何属性默认值。

10.【强制】序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值。

说明:注意serialVersionUID不一致会抛出序列化运行时异常。

19.【推荐】慎用Object的clone方法来拷贝对象。

说明:对象的clone方法默认是浅拷贝,若想实现深拷贝需要重写clone方法实现属性对象的拷贝。

(五)集合处理

1.【强制】关于hashCode和equals的处理,遵循如下规则:

1) 只要重写equals,就必须重写hashCode。因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。

2) 如果自定义对象做为Map的键,那么必须重写hashCode和equals。

2.【强制】ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList ;

说明:subList返回的是ArrayList的内部类SubList,并不是ArrayList,而是ArrayList的一个视图,对于SubList子列表的所有操作最终会反映到原列表上。

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

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

说明:asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

String[] str = new String[] { "a", "b" };List list = Arrays.asList(str);

第一种情况:list.add("c");运行时异常。

第二种情况:str[0]= "gujin";那么list.get(0)也会随之修改。

8.【强制】在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比较结果相同。

反例:下例中没有处理相等的情况,实际使用中可能会出现异常:

new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.getId() > o2.getId() ? 1 : -1;}} 


9.【推荐】集合初始化时,尽量指定集合初始值大小。

10.【推荐】使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。

11.【推荐】高度注意Map类集合K/V能不能存储null值的情况,如下表格: 

集合类

Key

Value

Super

说明

Hashtable

不允许为null

不允许为null

Dictionary

线程安全

ConcurrentHashMap

不允许为null

不允许为null

AbstractMap

分段锁技术

TreeMap

不允许为null

允许为null

AbstractMap

线程不安全

HashMap

允许为null

允许为null

AbstractMap

线程不安全

()并发处理

4.【强制】线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors返回的线程池对象的弊端如下:

1)FixedThreadPool和SingleThreadPool:

允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。

2)CachedThreadPool和ScheduledThreadPool:

允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

7.【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。

说明:线程一需要对表A、B、C依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是A、B、C,否则可能出现死锁。


14.【参考】HashMap在容量不够进行resize时由于高并发可能出现死链,导致CPU飙升,在开发过程中注意规避此风险。 


()控制语句

7.【参考】方法中需要进行参数校验的场景:

1)调用频次低的方法。

2)执行时间开销很大的方法,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,那得不偿失。

3)需要极高稳定性和可用性的方法。

4)对外提供的开放接口,不管是RPC/API/HTTP接口。5) 敏感权限入口。

8.【参考】方法中不需要参数校验的场景:

1)极有可能被循环调用的方法,不建议对参数进行校验。但在方法说明里必须注明外部参

数检查。

2)底层的方法调用频度都比较高,一般不校验。毕竟是像纯净水过滤的最后一道,参数错

误不太可能到底层才会暴露问题。一般DAO层与Service层都在同一个应用中,部署在同一

台服务器中,所以DAO的参数校验,可以省略。

3)被声明成private只会被自己代码所调用的方法,如果能够确定调用方法的代码传入参

数已经做过检查或者肯定不会有问题,此时可以不校验参数。

()异常处理 

3.【强制】对大段代码进行try-catch,这是不负责任的表现。catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。

9.【推荐】方法的返回值可以为null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回null值。调用方需要进行null判断防止NPE问题。说明:本规约明确防止NPE是调用者的责任。即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败,运行时异常等场景返回null的情况。

()日志规约

1.【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

import org.slf4j.Logger;import org.slf4j.LoggerFactory;private static final Logger logger = LoggerFactory.getLogger(Abc.class);

() SQL规约 

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

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

() ORM规约 

4.【强制】xml配置中参数注意使用:#{},#param#不要使用${}此种方式容易出现SQL注入。

8.【推荐】不要写一个大而全的数据更新接口,传入为POJO类,不管是不是自己的目标更新字段,都进行update table set c1=value1,c2=value2,c3=value3;这是不对的。执行SQL时,尽量不要更新无改动的字段,一是易出错;二是效率低;三是binlog增加存储。

0 0
原创粉丝点击