点击关注公众号,实用开发笔记及时了解
早上好,我是 DeveloperWang,one developer~
毕玄:
一个优秀的工程师和一个普通工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。
阿里 Java 开发手册
《Java 开发手册》由孤尽编著,是阿里巴巴集团技术团队的集体智慧结晶和经验总结,经历了多次大规模一线实战的检验及不断完善,公开到业界后,众多社区开发者踊跃参与,共同打磨完善,系统化地整理成册,经过几次迭代,目前版本是泰山版。
如需获取该开发手册电子版pdf,在公众号回复 “开发手册” 关键字即可。
该开发手册出现的背景是,现代软件行业的高速发展对开发者的综合素质要求越来越高,因为不仅是编程知识点,其它维度的知识点也会影响到软件的最终交付质量。比如:数据库的表结构和索引设计缺陷可能带来软件上的架构缺陷或性能风险;工程结构混乱导致后续维护艰难;没有鉴权的漏洞代码易被黑客攻击等等。所以该手册以 Java 开发者为中心视角,划分为 编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约 七个维度,再根据内容特征,细分成若干级子目录。
另外,依据约束力强弱及故障敏感性,规约依次分为强制、推荐、参考三大类。在延伸信息中,“说明”对规约做了适当扩展和解释;“正例”提倡什么样的编码和实现方式;“反例”说明需要提防的雷区,以及真实的错误案例。
该开发手册的愿景是 码出高效,码出质量。
阿里同步于 2017 年在杭州云栖大会上发布了配套的 Java 开发规约 IDE 插件。当时还写了一篇记录了插件的安装使用:《阿里巴巴Java开发规约》插件使用之IntelliJ IDEA篇。
二房库依赖之枚举项
本次笔记主要分析该手册的工程结构部分之二方库依赖中关于枚举类型的使用注意事项。

【强制】二方库里可以定义枚举类型,参数可以使用枚举类型,但是接口返回值不允许使用枚举类型或者包含枚举类型的 POJO 对象。
这里有必要了解一下什么是二方库?
二方库 也称作二方包,一般是指发布到公司内部私服上面的 jar 包,可以供公司内部其他服务依赖使用;
一方库 是指本工程内部子项目模块依赖的库;
三方库 是指公司之外的开源库,比如常见的 Spring、Mybatis、Dubbo 等等。
那为什么手册中会对接口返回值作出关于枚举类型使用的限制呢?
这是对于二方库而言,接口一般由提供方进行定义并实现,然后部署。真实调用过程中,消费方发起一次 RPC 调用,提供方服务处理完用户请求后由序列化框架(Dubbo 中对应 Hessian 框架)将响应信息进行序列化成字节流,然后传输给消费方服务,再由消费方服务对字节流进行反序列化成对象。
如果提供方在接口返回类型中定义了枚举类型字段,当这个枚举类型字段没有发生更改之前,一切都是正常的,请求可以正常处理,并正常响应。但是如果某天,由于提供方的业务需求或者技术改造,需要调整该枚举类型字段(新增或删除一个枚举属性),然后提供方升级了接口版本。这是如果提供方没有及时通知消费方,或者消费方由于某种原因不能及时同步配合提供方进行发布,就会导致接口调用异常,提示不合法的枚举属性。因为提供方服务返回的枚举类型数据,并不存在于消费方所引用的旧版本库中。
这个异常("No enum constant …")来源于 JDK 中枚举类中的 valueOf() 方法中:

那为什么参数中可以使用枚举类型呢?
因为枚举类型是由提供方进行维护的,提供方包含的枚举类型属性肯定是多于等于消费方的枚举类型属性的,所以接口的入参中使用枚举类型是不会出现问题的。而返回值里面就不一样了,如果提供方返回了一个消费方不认识的枚举属性,就会抛出上述的异常。
这里附上孤尽老师关于这条规定的回答:
由于升级原因,导致双方的枚举类不尽相同,在接口解析,类反序列化时出现异常。Java 中出现的任何元素,在 Gosling 的角度都会有背后的思考和逻辑(尽管并非绝对完美,但 Java 的顶层抽象已经是天才级了),比如:接口、抽象类、注解、和本文提到的枚举。枚举有好处,类型安全,清洗直接,还可以使用等号来判断,也可以用在 switch 中。它的劣势也是明显的,就是不要扩展。可是为什么在返回值和参数进行了区分呢,如果不兼容,那么两个都有问题,怎么允许参数可以有枚举。当时的考虑,如果参数也不能用,那么枚举几乎无用武之地了。参数输出,毕竟是本地决定的,你本地有的,传送过去,向前兼容是不会有问题的。但如果是接口返回,就比较恶心了,因为解析回来的这个枚举值,可能本地还没有,这时就会抛出序列化异常。
比如:你的本地枚举,有一个天气 Enum:SUNNY,RAINY,CLOUDY,如果根据天气计算心情的方法:guess(WeatherEnum xx),传入这三个值都是可以的。返回值:Weather guess(参数),那么对方运算后,返回一个 SNOWY,本地枚举里没有这个值,傻眼了。
小结
通过上述场景,考虑到使用枚举类型可能存在兼容性的问题,我们在实际项目中可以使用基本类型或者相应的包装类型来代替枚举类型,结合具体的业务场景而定。
这本《Java 开发手册》可以看作是 Java 开发领域的最佳实践,值得我们反复学习和思考。




