写点什么

高效能团队的 Java 研发规范 (进阶版)

作者:木小风
  • 2022 年 8 月 12 日
    北京
  • 本文字数:2804 字

    阅读完需:约 9 分钟

高效能团队的Java研发规范(进阶版)

目前大部分团队是使用的阿里巴巴 Java 开发规范,不过在日常开发中难免遇到覆盖不到的场景,本文在阿里巴巴 Java 开发规范基础上,补充一些常用的规范,用于提升代码质量及增强代码可读性。

编程规约

1、基础类型及操作

(1)转换

基本类型转换

String 类型转数字:使用 apache common-lang3 包中的工具类 NumberUtils,优势:可设置默认值,转换出错时返回默认值


NumberUtils.toInt("1");
复制代码


拆箱:包装类转化为基本类型的时候,需要判定 null,比如:


Integer numObject = param.get(0);int num = numObject != null ? numObject : 0;
复制代码
对象类型转换

使用 MapStruct 工具,转换类后缀 Convertor,所有转换操作都在转换类中操作,禁止在业务代码中编写大量 set 代码。

(2)判断

枚举判定

使用枚举判等,而非枚举对应的数字。因为枚举更直观,方便查看代码及调试,数字容易出错。

判空

各种对象的判空:


//对象判空&非空Objects.isNull()Objects.nonNull()
//String判空&非空StringUtils.isEmpty() //可匹配null和空字符串StringUtils.isNotEmpty()StringUtils.isBlank() //可匹配null、空字符串、多个空白字符StringUtils.isNotBlank()
//集合判空&非空CollectionUtils.isEmpty()CollectionUtils.isNotEmpty()
//Map判空&非空MapUtils.isEmpty()MapUtils.isNotEmpty()
复制代码
断言

使用 Guava 里的 Preconditions 工具类,比如:


//如果是空则抛异常Preconditions.checkNotNull()//通用判断Preconditions.checkArgument()
复制代码

2、集合处理

(1)Map 快捷操作

推荐:


//如果值不存在则计算map.computeIfAbsent("key",k-> execValue(k));//默认值map.getOrDefault("key", DEFAULT_VALUE)
复制代码


反例:


//如果值不存在则计算String v = map.get("key");if(v == null){    v = execValue("key");    map.put("key", v);}//默认值map.containsKey("key") ? map.get("key") : DEFAULT_VALUE
复制代码

(2)创建对象

构造方法或 Builder 模式,超过 3 个参数对象创建使用 Builder 模式


//Java11+:List.of(1, 2, 3)  Set.of(1, 2, 3)Map.of("a", 1)
//Java8中不可变集合(需引入Guava)ImmutableList.of(1,2,3)ImmutableSet.of(1,2,3)ImmutableMap.of("key","value")//多值情况ImmutableMap.builder() .put("key", "value") .put("key2", "value2") .build()
//Java8中可变集合(需引入Guava)Lists.newArrayList(1, 2, 3)Sets.newHashSet(1, 2, 3)Maps.newHashMap("key", "value")
复制代码


反例:


new ArrayList<>(){{   add(1);   add(2);}};
复制代码

(3)集合嵌套

集合里的值如果是基础类型必须加上注释,说明集合里存的是什么,比如:


//返回值: Map(key: 姓名, value: List(商品))Map<String, List<String>> res;
复制代码


超过 2 层集合对象封装必须封装成自定义类:


//推荐Map<String, List<Node>> res;
@Valuepublic static class Node { /** * 备注说明字段 */ String name; /** * 备注说明字段2 */ List<Integer> subjectIds;}
//反例Map<String, List<Pair<String, List<Integer>>>> res;
复制代码

异常及日志

1、异常

关于异常及错误码的思考,请参考笔者的另一篇文章:错误码设计思考


异常除了抛异常还有一种场景,即:上层发起多个必要调用,某些可能失败,需要上层自行决定处理策略,推荐使用 vavr 中的 Either 类,Either 使用建议:通常我们使用左值表示异常,而右值表示正常调用后的返回结果,即: Either<Throwable, Data>

2、日志

(1)日志文件

根据日志等级一般分为 4 个日志文件即可:debug.log、info.log、warn.log、error.log;


如有特殊需求可根据场景单独建文件,比如请求日志:request.log、gc 日志:gc.log 等。

(2)所有用户日志都要有追踪字段

追踪字段包括:traceId、userId 等,推荐使用 MDC,常用的日志框架:Log4j、Logback 都支持。

(3)日志清理及持久化

本地日志根据磁盘大小,必须设置日志保存天数,否则有硬盘满风险;


分布式环境为了方便查询,需要将日志采集到 ES 中查询;


重要日志:比如审计日志、B 端操作日志需要持久保存,一般是保存到 Hive 中;

工具篇

1、JSON

推荐:使用 Gson 或 Jackson;


不推荐:Fastjson。Fastjson 爆出的漏洞多。

2、对象转换

推荐:MapStruct,根据注解编译成 Java 代码,没有反射,速度快;行为可预测,可查看编译后的 Java 代码查看转换逻辑;


不推荐:BeanUtils、Dozer 等。需要反射,行为不可预测,需要测试;


不推荐:超过 3 个字段手动转换;

3、模板代码

推荐:Lombok,减少代码行数,提升开发效率,自动生成 Java 代码,没有性能损耗;


不推荐:手动生成大量 set、get 方法;

4、参数校验

推荐:hibernate Validation、spring-boot-starter-validation,可通过注解自动实现参数拦截;


不推荐:每个入口(比如 Controller)都 copy 大量重复的校验逻辑;

5、缓存

推荐:Spring Cache,通过注解控制缓存逻辑,适合常用的加缓存场景。

设计篇

1、正向语义

正向语义的好处在于使代码容易理解。 比如:if(judge()){....},很容易理解,即:判定成功则执行代码块。


相反,如果是负向语义,思维还要转换一下,一般用于方法前置的参数校验。


正向语义的应用场景有:


  • 方法定义:方法名推荐:canPass、checkParam,返回 true 代表成功。 不推荐:比如 isInvalidParam 返回 true 代表失败,增加理解成本;

  • Lambda 表达式:filter 操作符中返回 true 是可以通过的元素;

  • if 和三目运算符:condition ? doSomething() : doSomething2() , 条件判定后紧跟的是判定成功后执行的操作。


反例:


if (!judge()) {   doSomething2()} else {   doSomething()}
复制代码

2、防御式编程

(1)外部数据校验

外部传过来数据都需要校验,一般分为两类:


  • 数据流入:用户 Http 请求、RPC 请求、MQ 消费者等

  • 数据依赖:依赖的第三方 RPC、数据库等


如果是数据流入,一定要首先校验数据合法性再往下执行,推荐 hibernate Validation 这类工具,可以很方便的做数据校验


数据是数据依赖,一定要考虑各种网络、限流、背压等场景,做好熔断、降级保障。推荐建立防腐层,将第三方的限界上下文语义转换为当前上下文语义,避免理解上的歧义;

(2)Null 处理

  • 对于强依赖,没有返回值不行(比如查询数据库):直接抛异常;

  • 需要反馈给上层处理:

  • (1)可能返回 null 的场景:使用 Optional;

  • (2)上层需要感知信息异常信息:使用 vavr 中的 Either;

  • 可降级:

  • (1)返回值是默认值:集合类返回,数字返回 0 或-1,字符串返回空字符串,其他场景自定义

  • 集合默认值:


Collections.emptyList()  //空ListCollections.emptySet()   //空SetCollections.emptyMap()   //空Map
复制代码

总结

本文总结了 Java 开发常用的高级规范,暂时想到这么多,对文章中观点感兴趣,欢迎留言或加微信交流。


作者博客链接:Java研发规范(进阶版)


作者简介:木小丰,美团 Java 技术专家,专注分享软件研发实践、架构思考。欢迎关注公共号:Java 研发


更多精彩文章:


错误码设计思考


Java线程池进阶


从MVC到DDD的架构演进


平台化建设思路浅谈


构建可回滚的应用及上线checklist实践

发布于: 刚刚阅读数: 6
用户头像

木小风

关注

美团技术专家。公共号:Java研发 2012.03.22 加入

还未添加个人简介

评论

发布
暂无评论
高效能团队的Java研发规范(进阶版)_编程规范_木小风_InfoQ写作社区