阿里巴巴的 Java 开发手册(黄山版)来了
0. 阅读完本文你将会学会
写出更优雅高效的 Java 代码
1. 前言
周六逛 B 乎的时候正好刷到这样一个问题 "Java 开发手册(黄山版)怎么样?",我仔细一看这不是孤尽老师的著作吗?居然已经更新到了黄山版。
上次看这本小册子的时候还是上次——19 年的时候我看的华山版的。再往前那就是 17 年的第一版了,当时是在阿里的公众号下载的,后来还买了实体的《Java 开发手册》和《码出高效》两本书。
其实这本小册子并不是什么深度的内容,但是却让我受益匪浅——你写不出复杂高深的代码,但是至少能写出规范、干净、同事看了不喊“卧槽”而是喊“卧槽牛逼”的代码。
在这篇文章中我将会挑选几条手册中的编程规约做一个简单的导读。
友情提示,文末有手册下载方式哦。
对软件来说,适当的 规范和标准绝不是消灭代码内容的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,提升协作效率,降低沟通成本。代码的字里行间流淌的是软件系统的血液,代码质 量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升系统稳定性,码出质量。
2. 编程规约导读
2.1 禁用魔法值
不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。
魔法值指的是代码中没有任何定义,直接像魔法一样凭空出现的值,可以是数字、字符串等。
这是我印象中比较深的一条强制性规约。
当我刚入这行的开始写代码的时候,魔法值满天飞,怎么方便怎么来。根本不会考虑这样的问题,但是后来这样做的恶性后果也就出现了。
重复性的魔法值,不够简洁,逼死喜欢复用的强迫症!
容易出现像上面反例一样的错误,比如下划线少了啊或者一个单词拼错了。
魔法值难以简明地阐述其含义。比如,代码中直接出现的"0"和"1",谁知道它的含义呢?
所以,我们是可以通过静态常量或者枚举来定义你的常量,这样就可以把魔法值消灭殆尽。
2.2 访问权限控制从严
类成员与方法访问控制从严。
如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。
工具类不允许有 public 或 default 构造方法。
类非 static 成员变量并且与子类共享,必须是 protected。
类非 static 成员变量并且仅在本类使用,必须是 private。
类 static 成员变量如果仅在本类使用,必须是 private。
若是 static 成员变量,考虑是否为 final。
类成员方法只供类内部调用,必须是 private。
类成员方法只对继承类公开,那么限制为 protected。
这条是推荐性编程规约,其实这样的规约正是体现了 Java 的特性之一——封装性。
对于任何类、方法、参数、变量,我们都应该严格控制其访问范围。太过宽泛的访问范围,不利于模块解耦。
我自己写代码的时候,也是 private 够用就用 private。
孤尽在手册里提出了一个很有意思的问题:
如果是一个 private 的方法,想删除就删除,可是一个 public 的 service 成员方法或成员变量,删除一下,不得手心冒点汗吗?
他做了这样一个比喻:
变量像自己的小孩,尽量在自己的视线内,变量作用域太大,无限制的到处跑,那么你会担心的。
我觉得这真是说到点子上了。
2.3 for 循环中 list 禁用 remove/add
不要在 foreach 循环里进行元素的 remove / add 操作。remove 元素请使用 iterator 方式, 如果并发操作,需要对 iterator 对象加锁。
这条强制性规约的坑我也踩过,在反例中,当它执行了 remove 操作,会报如下错。
java.util.ConcurrentModificationException
具体的原因不在此文赘述,有兴趣的读者朋友可以网上查阅。
2.4 命名复杂布尔表达式
除常用方法(如 getXxx / isXxx)等外不要在条件判断中执行其它复杂的语句,将复杂逻辑判 断的结果赋值给一个有意义的布尔变量名,以提高可读性。
这条推荐性规约也是我推崇备至的。因为业务需要,我们可能在 if 语句中写出非常复杂的逻辑表达式。与、或、取反混合运算,甚至各种方法调用,理解起来非常难。
如果我们赋予这样一个逻辑表达式一个很好理解的名字(我觉得比注释更简洁易懂方便),则是一件令人赏心悦目的事情。
我们来看一个对比的例子:
2.5 异常处理
catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定 代码的 catch 尽可能进行区分异常类型,再做对应的异常处理。
看到这条强制性规约的时候,我老脸一红。
因为我曾经也犯过这样的错——对大段代码进行 try-catch,这样做会使程序无法根据不同的异常做出正确的应激反应,也不利于定位问题,这是一种不负责任的表现。
用户注册的场景中,如果用户输入非法字符,或用户名称已存在,或用户输入密码过于简单,我们应该在程序上作出分门别类的判断,并提示给用户。
2.6 日志规约
生产环境禁止使用 System.out 或 System.err 输出或使用 e.printStackTrace() 打印异常堆栈。
使用 e.printStackTrace() 打印日志容易占用太多内存,造成锁死。
要打印字符串输出到控制台上,需要字符串常量池所在的内存块有足够的空间。然而,因为 e.printStackTrace() 语句要产生的字符串记录的是堆栈信息,太长太多,内存被填满了!大量线程产出字符串产出到一半,等待有内存被释放,锁死了,导致整个应用挂掉了。
另外,日志交错混合,不易读。
printStackTrace()默认使用了 System.err 输出流进行输出,与 System.out 是两个不同的输出流,那么在打印时自然就形成了交叉。再就是输出流是有缓冲区的,所以对于什么时候具体输出也形成了随机。
一般打印错误日志的时候我们都是用日志框架的log.error("",e)
,基本够用了。
2.7 数据库
小数类型为 decimal,禁止使用 float 和 double。
这是一条强制性规约,在存储的时候,float 和 double 都存在精度损失的问题,很可能在比较值的时候,得到不正确的结果。
如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数并分开存储。
3.结语
以上是我从手册中摘录的几条规约,加之一些简单的导读。不知道各位看官老爷们有没有一些似曾相识的感觉呢?
手册一共有七个章节,基本上囊括了 Java 程序员写代码的方方面面。
如何获取手册,写出更优雅高效的代码,请关注我的公众号 "花园野人",回复 "pdf1",即可获取孤尽老师的 Java 开发手册。
感谢收看本期的翊君 @周一电台。如果你觉得还不错的话,快给我三连支持一下吧,咱们下期不见不散呐。
版权声明: 本文为 InfoQ 作者【翊君】的原创文章。
原文链接:【http://xie.infoq.cn/article/49c96b5f338f4b7afb269ba8a】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论