Skip to content

写 JAVA 的好习惯

前言

好的开发习惯能帮助我们在日常开发工作中达到事半功倍的效果,增强代码的可读性、健壮性,减少代码漏洞,因此我们应当不懈的追求代码精进,培养好的开发习惯。

代码规范

  • 写完代码,自测一下
  • 方法入参尽量都校验
  • 对于复杂的代码逻辑,添加清楚的注释
  • 使用完 IO 资源流,需要关闭
  • 代码采取措施避免运行时错误(如数组边界溢出,被零除等)
  • 尽量不在循环里远程调用、或者数据库操作,优先考虑批量进行
  • 获取对象的属性,先判断对象是否为空
  • Set 集合或者 Map 集合中的 key 为自定义对象时,要重写该对象的 equalshashCode 方法
  • 避免使用双括号 的方式实例化对象,该写法虽然简洁但会生成匿名内部类,容易造成内存泄漏
js
  new Person{{setName('xxx')}}
  • 不要在条件判断中写复杂的表达式
  • 条件判断使用卫语句,增强代码可读性和健壮性
  • 使用 equals()方法时,常量(有确定值)放前面
  • spring 官方推荐使用构造器注入
  • 尽量不在循环中使用 try-catch,应把其放在最外层
  • 常量声明为 static final,并以大写命名
  • 不要创建一些不使用的对象,不要导入一些不使用的类
  • 不要对超出范围的基本数据类型做向下强制转型

代码优化

  • 尽量指定类、方法、变量的 final 修饰符
  • 尽量重用对象
  • 尽可能使用局部变量
  • 尽量减少对变量的重复计算
  • 尽量采用懒加载的策略
  • 如果能预估到数组、集合的内容长度,应在创建时指定长度
  • 复制大量数据时,使用 System.arraycopy()
  • 乘法和除法使用移位操作
  • 数组优先于列表
  • 尽量在合适的场合使用单例
  • 尽量避免使用静态变量
  • 尽量避免使用反射
  • 尽量使用池化技术(数据库连接池、线程池)
  • 使用带缓冲的输入输出流进行 IO 操作
  • public 方法不要有太多的形参
  • 使用最有效率的方式去遍历 Map(推荐使用 entrySet()遍历)

接口规约

  • 接口需要考虑幂等性
  • 接口入参需要做校验,推荐使用@valid 或者@validated 校验框架
  • 接口出参不允许为枚举值或任何包含枚举值的 pojo 对象
  • 修改老接口的时候,考虑接口的兼容性
  • 调用第三方接口,需要考虑异常处理,安全性,超时重试这几个点

并发编程

  • 多线程情况下,考虑线性安全问题
  • 写完代码,脑洞一下多线程执行会怎样,注意并发一致性问题
  • 多线程异步优先考虑恰当的线程池,而不是 new thread,同时考虑线程池是否隔离
  • 使用ThreadPoolExecutor构造器创建线程池,避免使用 Executors 的 静态方法创建线程池
  • 使用 synchronized 时尽量同步代码块
  • 使用锁时尽量缩小锁定范围

缓存(redis

  • 使用缓存的时候,考虑缓存跟 DB 的一致性
  • 考虑缓存穿透、缓存雪崩、缓存击穿、缓存热点问题
  • 避免使用 redis 事务功能
  • 禁止线上使用keysflushallflushdb 等,通过 redisrename 机制禁掉命令,或者使用 scan 的方式渐进式处理
  • 使用批量操作的命令提升效率
  • 拒绝 big key(拆分 key ,使用合适的数据类型)
  • 控制 key 的生命周期(分散设置过期时间)
  • key 名设计要有可读性、可管理性、简洁性,不要包含特殊字符
  • 设置合适的内存淘汰策略

数据库

  • 手动写完代码业务的 SQL ,先拿去数据库跑一下,同时也 explain 看下执行计划
  • 数据库主从延迟问题考虑(必要时强制读主库)
  • 避免在循环内做数据库的操作

SQL 规范

  • 设计表的时候,所有表和字段都添加相应的注释
  • SQL 书写格式,关键字大小保持一致,使用缩进
  • INSERT 语句标明对应的字段名称
  • 设计数据库表的时候,加上以下个字段(字段名可自定义):主键,create*timeupdate_timedelete_flag
  • 尽量把所有列定义为 NOT NULL 并提供默认值
  • 所有表必须使用 Innodb 存储引擎
  • 数据库和表的字符集尽量统一使用 utf8/utf8mb4
  • 如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释
  • 索引命名要规范,主键索引名为pk*字段名;唯一索引名为 uk*字段名;普通索引为 idx_字段名
  • 禁止使用外键,如果有外键完整性约束,由应用程序控制

索引规范

  • 避免在更新比较频繁、区分度不高的列上单独建立索引
  • 需要 JOIN 的字段,数据类型必须绝对一致; 多表关联查询时,保证被关联的字段需要有索引
  • 建立联合索引时,必须将区分度更高的字段放在左边
  • 在一个联合索引中,若第一列索引区分度等于 1,那么则不需要建立联合索引
  • 利用覆盖索引来进行查询操作,避免回表

SQL 性能优化

  • 写完 SQLexplain 查看执行计划
  • 写完 SQL 语句,检查 whereorder bygroup by 后面的列,多表关联的列是否已加索引,优先考虑联合索引 where 后面的字段,留意其数据类型的隐式转换
  • 尽量使用 varchar 代替 char,如果存储的字符串长度几乎相等,则使用 char 定长字符串类型
  • 减少不必要的字段返回,如使用 select <具体字段> 代替 select *
  • where 从句中不对列进行函数转换和表达式计算
  • 如果修改/更新数据过多,考虑批量进行
  • 在一些场景下,考虑使用 timestamp 代替 datetime
  • 不使用%开头的模糊查询
  • 尽量避免在 WHERE 子句中使用 or 作为连接条件
  • JOIN 的表不允许超过五个(一般不允许超过三个)
  • 不分页的集合查询应规定查询数量的上限,避免全量查询导致 OOM

SQL 后悔药

  • 操作 delete 或者 update 语句,加个 limit
  • 变更 SQL 操作先在测试环境执行,写明详细的操作步骤以及回滚方案,并在上生产前 review
  • 修改或删除重要数据前,要先备份,先备份,先备份
  • 修改或者删除 SQL,先写 WHERE 查一下,确认后再补充 deleteupdate
  • SQL 命令行修改数据,养成 begin + commit 事务的习惯