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

编程规约

1、基础类型及操作

(1)转换

基本类型转换

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

  1. NumberUtils.toInt("1");

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

  1. Integer numObject = param.get(0);
  2. int num = numObject != null ? numObject : 0;
对象类型转换

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

(2)判断

枚举判定

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

判空

各种对象的判空:

  1. //对象判空&非空
  2. Objects.isNull()
  3. Objects.nonNull()
  4. //String判空&非空
  5. StringUtils.isEmpty() //可匹配null和空字符串
  6. StringUtils.isNotEmpty()
  7. StringUtils.isBlank() //可匹配null、空字符串、多个空白字符
  8. StringUtils.isNotBlank()
  9. //集合判空&非空
  10. CollectionUtils.isEmpty()
  11. CollectionUtils.isNotEmpty()
  12. //Map判空&非空
  13. MapUtils.isEmpty()
  14. MapUtils.isNotEmpty()
断言

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

  1. //如果是空则抛异常
  2. Preconditions.checkNotNull()
  3. //通用判断
  4. Preconditions.checkArgument()

2、集合处理

(1)Map快捷操作

推荐:

  1. //如果值不存在则计算
  2. map.computeIfAbsent("key",k-> execValue(k));
  3. //默认值
  4. map.getOrDefault("key", DEFAULT_VALUE)

反例:

  1. //如果值不存在则计算
  2. String v = map.get("key");
  3. if(v == null){
  4. v = execValue("key");
  5. map.put("key", v);
  6. }
  7. //默认值
  8. map.containsKey("key") ? map.get("key") : DEFAULT_VALUE

(2)创建对象

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

  1. //Java11+:
  2. List.of(1, 2, 3)
  3. Set.of(1, 2, 3)
  4. Map.of("a", 1)
  5. //Java8中不可变集合(需引入Guava)
  6. ImmutableList.of(1,2,3)
  7. ImmutableSet.of(1,2,3)
  8. ImmutableMap.of("key","value")
  9. //多值情况
  10. ImmutableMap.builder()
  11. .put("key", "value")
  12. .put("key2", "value2")
  13. .build()
  14. //Java8中可变集合(需引入Guava)
  15. Lists.newArrayList(1, 2, 3)
  16. Sets.newHashSet(1, 2, 3)
  17. Maps.newHashMap("key", "value")

反例:

  1. new ArrayList<>(){{
  2. add(1);
  3. add(2);
  4. }};

(3)集合嵌套

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

  1. //返回值: Map(key: 姓名, value: List(商品))
  2. Map<String, List<String>> res;

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

  1. //推荐
  2. Map<String, List<Node>> res;
  3. @Value
  4. public static class Node {
  5. /**
  6. * 备注说明字段
  7. */
  8. String name;
  9. /**
  10. * 备注说明字段2
  11. */
  12. List<Integer> subjectIds;
  13. }
  14. //反例
  15. 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() , 条件判定后紧跟的是判定成功后执行的操作。

反例:

  1. if (!judge()) {
  2. doSomething2()
  3. } else {
  4. doSomething()
  5. }

2、防御式编程

(1)外部数据校验

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

  • 数据流入:用户Http请求、RPC请求、MQ消费者等
  • 数据依赖:依赖的第三方RPC、数据库等

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

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

(2)Null处理

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

  • 需要反馈给上层处理:

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

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

  • 可降级:

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

    集合默认值:

  1. Collections.emptyList() //空List
  2. Collections.emptySet() //空Set
  3. Collections.emptyMap() //空Map

总结

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

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

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

更多精彩文章:

错误码设计思考

Java线程池进阶

从MVC到DDD的架构演进

平台化建设思路浅谈

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

高效能团队的Java研发规范(进阶版)的更多相关文章

  1. 高效能团队协作的JIRA实践

    http://www.csdn.net/article/2015-05-21/2824739?utm_source=tuicool 高效能团队是企业生存和发展的基石.任何企业面对当下的激烈竞争,要想脱 ...

  2. 高淇java300集JAVA面向对象的进阶作业

    一.选择题 1.使用权限修饰符(B)修饰的类的成员变量和成员方法,可以被当前包中所有类访问,也可以被它的子类(同一个包以及不同包中的子类)访问.(选择一项) Apublic B.protected C ...

  3. DevOps|高效能敏捷交付组织:特性团队(FeatureTeam)+Scrum

    这是<研发效能组织能力建设>的第三篇.特性团队和Scrum,这两个定义我们在之前的文章中都详细介绍了.这两个组织模式或者说管理实践,我都用过所以有些时候特别有感触.书本上纯粹的模式很容易理 ...

  4. Java八股文纯享版——篇②:并发编程

    注: 1.笔记为个人归纳整理,尽力保证准确性,如有错误,恳请指正 2.写文不易,转载请注明出处 3.本文首发地址 https://blog.leapmie.com/archives/c02a6ed1/ ...

  5. TFS 2017 培训 - 北京某银行科技部Java研发团队

    今天受邀和微软公司的朋友一起,为北京某银行科技部的两个Java研发团队做了一场TFS系统的技术培训. 按照需求分析>开发>编译>发布>测试的流程为研发团队做了全流程的介绍. 这 ...

  6. 十倍效能提升——Web 基础研发体系的建立

    1 导读 web 基础研发体系指的是, web 研发中一线工程师所直接操作的技术.工具,以及所属组织架构的总和.在过去提升企业研发效能的讨论中,围绕的主题基本都是——”通过云计算.云存储等方式将底层核 ...

  7. 学生党如何拿到阿里技术offer: 《2016阿里巴巴校招内推offer之Java研发工程师(成功)》

    摘要: 这篇文章字字珠玑,这位面试的学长并非计算机相关专业,但是其技术功底足以使很多计算机专业的学生汗颜,这篇文章值得我们仔细品读,其逻辑条理清晰,问题把握透彻,语言表达精炼,为我们提供了宝贵的学习经 ...

  8. 转!!Java代码规范、格式化和checkstyle检查配置文档

    为便于规范各位开发人员代码.提高代码质量,研发中心需要启动代码评审机制.为了加快代码评审的速度,减少不必要的时间,可以加入一些代码评审的静态检查工具,另外需要为研发中心配置统一的编码模板和代码格式化模 ...

  9. Java代码规范、格式化和checkstyle检查配置文档

    http://www.blogjava.net/amigoxie/archive/2014/05/31/414287.html 文件下载: http://files.cnblogs.com/files ...

随机推荐

  1. 上半年最中意的 GitHub 更新「GitHub 热点速览 v.22.21」

    2022 年的热点速览加入 GitHub 产品动态之后,这次的图片显示是最得我意的,因为可以提升图片查看人的看片体验.而 GitHub 社区方面,GitHub 官方发布了部分开源项目的新版本.与此同时 ...

  2. 通过CSS让图片变的清楚

    image { width: 100%; height: 100%; border-radius: 10upx; //让图片变清楚 image-rendering: -moz-crisp-edges; ...

  3. es的查询、排序查询、分页查询、布尔查询、查询结果过滤、高亮查询、聚合函数、python操作es

    今日内容概要 es的查询 Elasticsearch之排序查询 Elasticsearch之分页查询 Elasticsearch之布尔查询 Elasticsearch之查询结果过滤 Elasticse ...

  4. 最大流&最小割&费用流模版

    好久都没有搞博客了.想认真写又要准备文化课期末了. ISAP 流程: 原理就是dfs找增广路. 最基础的建反向边以便反悔就不说了. 但是记录一个dep(dis)表示层数,一开始BFS(从t开始,dis ...

  5. mysql 超时配置

    日志报错: No operations allowed after connection closed.; nested exception is com.mysql.jdbc.exceptions. ...

  6. Dubbo的基本使用

    Dubbo分为提供者和消费方  并且两者都要注册到ZK上 提供者 注解    @Service   这是dubbo包下的 消费组 注解    @Reference 远程注入 第一步导入依赖 <! ...

  7. Docker容器手动安装mysql(国内镜像)

    Docker手动安装mysql 1.创建centos镜像的容器 [root@localhost Tools]# docker run -i -d -h zabbix --name zabbix -p ...

  8. ubuntu使用postfix和AWS-SES发送邮件

    在日常开发中,邮件发送是个比较常见的场景.因此出现了很多相关的软件和服务,各大云厂商也推出自己的邮件服务.今天笔者就像大家介绍一种常见的组合,AWS的邮件服务 SES 与邮件服务器 postfix 的 ...

  9. 开发工具-Redis Desktop Manager下载地址

    更新记录 2022年6月10日 完善标题. 官方: https://github.com/uglide/RedisDesktopManager 免费打包版: https://github.com/le ...

  10. 【Java面试】数据库连接池有什么用?它有哪些关键参数?

    一个工作5年的粉丝找到我,他说参加美团面试,遇到一个基础题没回答上来. 这个问题是:"数据库连接池有什么用?以及它有哪些关键参数"? 我说,这个问题都不知道,那你项目里面的连接池配 ...