首页 > 代码库 > 《阿里巴巴Java开发手册(正式版》读记

《阿里巴巴Java开发手册(正式版》读记

前几天,阿里巴巴发布了《阿里巴巴Java开发手册(正式版》,第一时间下载阅读了一番。

不同于一般大厂内部的代码规范,阿里巴巴的这本Java开发手册,可谓包罗万象,几乎日常Java开发中方方面面都有所涉及。

在知乎上,也有关于这本开发手册的讨论十分热烈的帖子。

 

由于里面涉及的内容比较多,下面重点罗列下一些我读过之后十分赞同与持保留意见的条目:

(一)编码规范

(一)命名规约

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

看法:此条级别为强制,不过是有特殊的应用场景的,boolean类型变量加上is前缀无可厚非。举例来说,对于处理状态标志,我觉得isProcessed/processed/processFlag/processStatus,这四种写法都是很OK的。不过我个人可能更偏好用processed,比较简洁。当然此条目被列举在开发手册中,也是前人踩坑的教训,吸收一下挺好。

 

10. 【强制】杜绝完全不规范的缩写,避免望文不知义。
反例: AbstractClass“缩写”命名成 AbsClass;condition“缩写”命名成 condi,此类 随意缩写严重降低了代码的可阅读性。

看法:非常赞同,时常在公司项目代码中看到不能一眼看出含义的拼音或者英文缩写比如cashFlow缩写为CF,代码可读性降低很多。Java代码不要害怕变量名或者方法名过长,除非你能找到一个比原先短,并且含义完全相同的更好的命名。 

 

14. 【参考】枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。 说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。 正例:枚举名字:DealStatusEnum,成员名称:SUCCESS / UNKOWN_REASON。 

看法:级别被列为参考,代表此条目推荐程度不是太高。我的看法也是如此,其实枚举类命名后缀什么type啦,status都可以啊。

 

(二)常量定义

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

看法:挺好的规范,对于大型项目,按照业务功能/模块常量类分开维护还是很有必要的。

 

(三)格式规约

10. 【推荐】方法体内的执行语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义之间插入一个空行。相同业务逻辑和语义之间不需要插入空行。

看法:在方法内部,逻辑上互相较为独立的代码块之间加入一个空行,会看起来更为清楚。但是也不要太极端,每行代码之间都插入空行,显得反而看起来空洞。

 

(四)OOP规约

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

看法:非常赞同。曾经遇到一个bug,按条件筛选数据集怎么也查不出来,后来发现是实体类中一些字段被加入了默认值,导致查询的时候带上了这些莫名增加的筛选字段。

 

(五)集合处理

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

说明:ArrayList尽量使用ArrayList(int initialCapacity) 初始化。 

看法:非常赞同,在确定集合中元素个数的情况下,最好new的时候就指定好大小,这样不仅可以减少空间开销,也可以避免内存碎片的产生。

 

(五)并发处理

12.【推荐】通过双重检查锁(double-checked locking)(在并发场景)实现延迟初始化的优化问题隐患(可参考 The "Double-Checked Locking is Broken" Declaration),

推荐问题 解决方案中较为简单一种(适用于 JDK5 及以上版本),将目标属性声明为 volatile 型。 

看法:双重检查锁可能因为指令重排引发的线程安全问题在《Java并发编程实战》一书中有提及,然而这种延迟初始化的单例有特定的背景,过去机器内存资源比较珍贵。

现在的服务器动辄几十个G的内存,很多时候不要把问题搞得太复杂,饿汉式单例模式直接搞起就行。

 

(二)异常日志

(一)异常处理

1.【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请 将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的 内容。 

看法:private方法可以处理或者重抛异常,public方法处理异常,如果能这样做,可以大大降低异常处理逻辑紊乱/疏漏。

 

(三)MySQL规约

(一)建表规约

9. 【强制】表必备三字段:id, gmt_create, gmt_modified。 说明:其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。gmt_create, gmt_modified 的类型均为 date_time 类型。 

看法:整数类型的自增主键以及创建和修改时间确实是非常有必要的,但名字不一定得要是gmt_create,gmt_modified,类型不一定要datetime。整数类型的自增主键的必要性在于每次插入都在B+树的末尾,相比无序插入,split操作会少很多。

(二)索引规约

7.【推荐】建组合索引的时候,区分度最高的在最左边。

正例:如果 where a=? and b=? ,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即 可。 说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列。 

看法:建索引真是一门学问,比较简单的入门就是按照选择性来定索引。曾经看到公司项目库中有多重索引把删除标志位都给包括进去了,删除标志位虽然是sql查询语句的一部分,但选择性很低,建索引完全没必要。

《阿里巴巴Java开发手册(正式版》读记