阿里巴巴Java开发手册v1.2.0自查笔记

阿里推出《阿里巴巴Java开发手册》v1.2.0 版本,公开展示阿里技术团队内部Java规范标准,对一个Java码农裨益多多,值得一看。

相关推文:抢鲜下载 | 阿里 Java 开发手册最新完美版,千锤百炼始出炉

笔者在细阅过程中记录以下自己划出的点。

一、编码规范

(一)命名风格

  1. 【强制】POJO 类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。
    反例:定义为基本数据类型Boolean isDeleted;的属性,它的方法也是isDeleted(),RPC框架在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

  2. 【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
    正例:应用工具类包名为com.alibaba.open.util、类名为MessageUtils(此规则参考 spring 的框架结构)

  3. 【参考】各层命名规约:

  4. Service/DAO 层方法命名规约

1) 获取单个对象的方法用`get`做前缀。 
2) 获取多个对象的方法用`list`做前缀。
3) 获取统计值的方法用`count`做前缀。
4) 插入的方法用`save`(推荐)或`insert`做前缀。
5) 删除的方法用`remove`(推荐)或`delete`做前缀。
6) 修改的方法用`update`做前缀。
  1. 领域模型命名规约
1) 数据对象:`xxxDO`,`xxx`即为数据表名。
2) 数据传输对象:`xxxDTO`,`xxx`为业务领域相关的名称。
3) 展示对象:`xxxVO`,`xxx`一般为网页名称。
4) POJO 是 DO/DTO/BO/VO 的统称,禁止命名成`xxxPOJO`。

(二)常量定义

  1. 【推荐】不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。如:缓存相关的常量放在类:CacheConsts下;系统配置相关的常量放在类:ConfigConsts下。
    说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。

  2. 【推荐】常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。

  3. 跨应用共享常量:放置在二方库中,通常是client.jar中的constant目录下。

  4. 应用内共享常量:放置在一方库的modules中的constant目录下。
    反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在两个类中分别定义了表示 “是”的变量:
    类 A 中:public static final String YES = "yes";
    类 B 中:public static final String YES = "y";
    A.YES.equals(B.YES),预期是true,但实际返回为false,导致线上问题。

  5. 子工程内部共享常量:即在当前子工程的constant目录下。

  6. 包内共享常量:即在当前包下单独的constant目录下。

  7. 类内共享常量:直接在类内部private static final定义。

(三)代码格式

(四)OOP 规约

  1. 【强制】外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated注解,并清晰地说明采用的新接口或者新服务是什么。

  2. 【强制】不能使用过时的类或方法。 说明:java.net.URLDecoder中的方法decode(String encodeStr)这个方法已经过时,应该使用双参数decode(String source, String encode)。接口提供方既然明确是过时接口, 那么有义务同时提供新的接口;作为调用方来说,有义务去考证过时方法的新实现是什么。

  3. 【强制】Objectequals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals
    正例: "test".equals(object);
    反例: object.equals("test");
    说明:推荐使用java.util.Objects#equals(JDK7 引入的工具类)

  4. 【强制】所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较。
    说明:对于Integer var = ?-128127范围内的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑, 推荐使用equals方法进行判断。

  5. 关于基本数据类型与包装数据类型的使用标准如下:

  6. 【强制】所有的 POJO 类属性必须使用包装数据类型。

  7. 【强制】RPC 方法的返回值和参数必须使用包装数据类型。

  8. 【推荐】所有的局部变量使用基本数据类型。
    说明:POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何 NPE 问题,或者入库检查,都由使用者来保证。
    正例:数据库的查询结果可能是null,因为自动拆箱,用基本数据类型接收有 NPE 风险。
    反例:比如显示成交总额涨跌情况,即正负x%x为基本数据类型,调用的 RPC 服务,调用不成功时,返回的是默认值,页面显示:0%,这是不合理的,应该显示成中划线-。所以包装 数据类型的null值,能够表示额外的信息,如:远程调用失败,异常退出。

  9. 【强制】定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值
    反例:POJO 类的gmtCreate默认值为new Date();,但是这个属性在数据提取时并没有置入具体值,在更新其它字段时又附带更新了此字段,导致创建时间被修改成当前时间。

  10. 【强制】序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值。
    说明:注意serialVersionUID不一致会抛出序列化运行时异常。

  11. 【强制】POJO 类必须写toString方法。使用 IDE 中的工具:source > generate toString 时,如果继承了另一个 POJO 类,注意在前面加一下super.toString
    说明:在方法执行抛出异常时,可以直接调用 POJO 的toString方法打印其属性值,便于排查问题。

  12. 【推荐】使用索引访问用Stringsplit方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛IndexOutOfBoundsException的风险。
    说明:

String str = "a,b,c,,";
String[] ary = str.split(","); // 预期大于 3,结果是 3
System.out.println(ary.length);

笔者注:
不要忘了这个好方法:String.split(String regex, int limit)

  1. 【推荐】类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法。说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为方法信息价值较低,所有 Service 和 DAO 的getter/setter方法放在类体最后。

  2. 【推荐】final可以声明类、成员变量、方法、以及本地变量,下列情况使用final关键字:

  3. 不允许被继承的类,如:String类。

  4. 不允许修改引用的域对象,如:POJO 类的域变量。

  5. 不允许被重写的方法,如:POJO 类的setter方法。

  6. 不允许运行过程中重新赋值的局部变量。

  7. 避免上下文重复使用一个变量,使用final描述可以强制重新定义一个变量,方便更好地进行重构。

(五)集合处理

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

  2. 只要重写equals,就必须重写hashCode

  3. 因为Set存储的是不重复的对象,依据hashCodeequals进行判断,所以Set存储的对象必须重写这两个方法。

  4. 如果自定义对象做为Map的键,那么必须重写hashCodeequals
    说明:String重写了hashCodeequals方法,所以我们可以非常愉快地使用String对象作为 key 来使用。

  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)也会随之修改。

To be continued...

你可能感兴趣的:(阿里巴巴Java开发手册v1.2.0自查笔记)