我们引用阿里的Java开发手册作为后端开发规范要求。

这里是它的地址:

以下按照正文结构进行要点总结(更详细的必须阅读原文)。

此外,这个开发手册还涉及到了和前端开发以及数据库设计有关的内容,也需要我们加以学习。

一、编程规约

(一)命名风格

  1. 禁止中英文混用的命名,除非是具有国际化语义的专有名词。例如:alibaba、taobao。推荐IDEA安装翻译插件【Translation】
  2. 包名统一小写,统一使用单数形式
  3. 类名统一使用大驼峰形式,可以使用复数形式,含设计模式/使用语义的要在命名上有所体现。特殊情况:DO / BO / DTO / VO / AO / PO / UID 等
  4. POJO类中,不要使用is_xxx命名风格的布尔型变量,否则其取值方法isXxx()容易令框架序列化错误
  5. 不要采用随意的英文缩写,尤其不要再前后端交互的变量上,增加沟通成本。特殊情况:msg等
  6. 枚举类带上Enum后缀,在引用枚举的String属性上通过{@link Enum}的形式标明。枚举类应按业务场景,分包维护起来,不要大而全。
  7. (推荐)除有明显的时间态,有根据数字大小判断进程的类型字段,例如配送状态以外,尽量减少直接使用数字作为枚举。
  8. service/dao层方法以动词开头,获取单个对象以get做前缀,多个对象以list做前缀等

    (二)常量定义

  9. 不允许任何魔法值。魔法值会随着业务发展越藏越深,产生问题

  10. 注意常量的访问限制符,不要无脑public
  11. 同一个工程的通用枚举,应统一维护。例如“Y/N”、“YES/NO”

    (三)代码格式

  12. 注意空格/换行等问题,写完一个方法,及时格式化一下代码。IDEA快捷键“CTRL+ALT+T”

  13. 二目/三目运算符左右需要空格,不要全部挤在一块
  14. 注释的双斜线和注释内容间有且仅有一个空格
  15. 注释掉的代码块,如果有恢复的可能,需要使用三个斜线进行说明,例如:/// 等待开启活动
  16. 单行代码字符不超120个,注意换行规范
  17. 单个方法行数不超过80行。推荐使用IDEA提供的refactor->extract功能,重构代码,分清红花与绿叶。注意提取出来方法的访问修饰符要不能无脑public/private
  18. 方法参数在定义和传入时,多个参数逗号后面必须加空格
  19. 不同逻辑/语义/业务间的代码,用一个空行间隔就够了,不必要多个换行
  20. 出现多组重复代码时,要考虑进行代码重构。getter方法的使用也能重构。

    (四)OOP规约

  21. 尽量不要使用过期的类/方法,使用前需要了解其替代方案

  22. 提供的参数/方法过期时,及时标记@Deprecated,并说明过期原因和新方案
  23. 使用Object的equals方法时,需要将常量/确定有值的对象作为左操作对象,避免NPE
  24. 基本类型的包装类进行数组比较时,也使用equals方法
  25. (阿里强制)货币金额,数据类型均以最小货币单位整型存储。例如分。
  26. 浮点数,包括float及其包装类Float的数值比较,不能单纯用==或equals判断。解决方案:一、规定一个最小允许差值;二、使用BigDecimal进行转换
  27. BigDecimal对象的数值比较,不能单纯使用equals方法,应使用compareTo()方法,因为BigDecimal对象属性包括数值和小数范围scale
  28. 禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。推荐使用BigDecimal.valueOf()方法或则入参为字符串的构造方法
  29. 关于基本数据类型和包装数据类型选择:

    1) 【强制】所有的 POJO 类属性必须使用包装数据类型。 2) 【强制】RPC 方法的返回值和参数必须使用包装数据类型。 3) 【推荐】所有的局部变量使用基本数据类型。

  30. (阿里强制)定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值。

说明:如果确实有使用需求,注意@Builder标注的类,不能直接采用“属性 = 初始值”的方式赋值,需要标记@Builder.default,并配合.build()方法使用。
new出来的对象和build出来的对象,其默认值策略有冲突。

  1. 有序列化需求的类,如缓存到redis、存到文件上等,统一加上 serialVersionUID 字段,避免版本变更引起序列化异常
  2. 循环体内连接字符串,推荐使用StringBuilder
  3. 类成员和方法的访问权限需要控制从严,按需公开,减少改代码的风险

    (五)日期时间

  4. 日期格式化pattern中,注意大小写。标准格式“yyyy-MM-dd HH:mm:ss”

  5. 避免使用写死的月份天数、年份天数等
  6. 注意日期API中年份、星期范围首值问题。

    (六)集合处理

  7. Set集合和Map的key值,都需要进行equals和hashCode方法的重写。平时用的String类已重写了。

  8. Map的keySet()/values()/entrySet()方法等返回集合对象时,不可对其进行元素添加/删除操作
  9. Collections的emptyList()/singletonList()返回值,也不可对其进行元素添加/删除操作
  10. 工具类Arrays.asList()方法返回的集合,不能使用元素修改操作
  11. 集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一致、长度为 0 的空数组
  12. 使用Collection的实现类的addAll方法,需要对入参进行NPE校验
  13. 不要在集合的foreach循环中进行remove/add操作。请使用iterator方式
  14. 遍历Map推荐采用Map.entrySet或则Map.forEach方法
  15. 可以利用Set的元素唯一特性进行数据去重操作
  16. (补充)Java8及以上推荐使用流特性进行集合操作,简化代码

    (七)并发处理

  17. 单例模式需要进行并发控制,推荐使用二重锁

  18. 线程资源应由线程池提供,不要手动创建新线程
  19. SimpleDateFormat是线程不安全的类,可以使用ThreadLocal规避,也推荐使用JDK8及以上的DateTimeFormatter(线程安全)
  20. 高并发场景下的锁控制,锁范围需尽可能减小

    (八)控制语句

  21. switch语句,每一个case,要有明确的break/return。switch末尾,应有default处理

  22. switch语句需要对入参进行空值判断,避免业务错误
  23. 三目运算符condition ? 表达式1:表达式2中,表达式1和表达式2需要使用相同类型,避免拆箱产生数据异常
  24. 减少if()...else if()...else...等表达式的使用,尽可能采用“卫语句”
  25. if语句内不要使用复杂表达式,如有必要,请进行变量提取
  26. 赋值语句单独占一行,不要搞捉迷藏
  27. 不要使用“反向逻辑”,尽量都使用“正向逻辑”
  28. 公共接口需要做入参保护,尤其是批量操作接口,需要考虑阈值问题
  29. 越顶层的方法,越要进行参数校验

    (九)注释规约

  30. 类、类属性、类方法的注释需要使用Javadoc规范。(补充:设计第三方的POJO类更加需要注释)

  31. 接口以及抽象方法,必须使用Javadoc注释,说明该方法的业务逻辑。(补充:可以配合{@link}以及{@see}等注释说明)
  32. 不要使用行尾注释。方法内的单行注释写在被注释代码上方,独占一行,//后面有且仅有一个空格
  33. 代码的更新需要及时同步注释内容,尤其是修正接口注释,修正方法名等
  34. 利用代码重构的艺术,尽量做到代码自解释
  35. TODO内容应标记处理人/标记时间/[预计处理时间]

    (十)前后端规约

  36. 前后端交互的JSON数据,属性名应是小驼峰风格。(补充:第三方的一些特殊属性可以例外,如openid)

  37. 对于需要使用超大整数的场景,后端采用String字符串类型返回,不要使用Long类型,防止数据范围丢失
  38. (推荐)前后端的时间格式统一为“yyyy-MM-dd HH:mm:ss”,统一为GMT
  39. (参考)接口版本后控制在HTTP头

    (十一)其他

  40. 即时清理垃圾代码、过时配置

    二、异常日志

    (一)错误码

    (二)异常处理

  41. 能预检的异常,例如NPE,不要通过catch的方式处理

  42. 不要试图通过异常捕获进行流程控制
  43. 不要对大块代码进行try-catch操作,稳定代码不要包裹进去。catch的异常也应尽可能进行类型区分
  44. 异常catch下来之后,必须合理处理,内部无法处理请再业务记录/处理后抛给上层,并在方法注释声明
  45. 事务场景下catch了异常,如需要事务回滚,请手动回滚或抛出异常
  46. 调用RPC、二方包等相关方法时,捕获异常必须使用Throwable类来进行拦截。(补充:需与自身服务异常进行区分)

    (三)日志规约

  47. 不要直接使用日志系统实现的API,应应该使用门面模式的日志框架,推荐使用SLF4J

  48. 日志打印时禁止使用JSON工具将对象转换成String,防止getter方法重写导致异常
  49. 字符串使用{}占位
  50. 英文日志如果描述不清楚,请使用中文日志
  51. catch异常进行error日志记录,如log.error("XXX异常", e )