夜间模式
写 JAVA 的好习惯
前言
好的开发习惯能帮助我们在日常开发工作中达到事半功倍的效果,增强代码的可读性、健壮性,减少代码漏洞,因此我们应当不懈的追求代码精进,培养好的开发习惯。
代码规范
- 写完代码,自测一下
- 方法入参尽量都校验
- 对于复杂的代码逻辑,添加清楚的注释
- 使用完
IO
资源流,需要关闭 - 代码采取措施避免运行时错误(如数组边界溢出,被零除等)
- 尽量不在循环里远程调用、或者数据库操作,优先考虑批量进行
- 获取对象的属性,先判断对象是否为空
Set
集合或者Map
集合中的key
为自定义对象时,要重写该对象的equals
和hashCode
方法- 避免使用双括号
的方式实例化对象,该写法虽然简洁但会生成匿名内部类,容易造成内存泄漏
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
事务功能 - 禁止线上使用
keys
、flushall
、flushdb
等,通过redis
的rename
机制禁掉命令,或者使用 scan 的方式渐进式处理 - 使用批量操作的命令提升效率
- 拒绝
big key
(拆分key
,使用合适的数据类型) - 控制
key
的生命周期(分散设置过期时间) key
名设计要有可读性、可管理性、简洁性,不要包含特殊字符- 设置合适的内存淘汰策略
数据库
- 手动写完代码业务的
SQL
,先拿去数据库跑一下,同时也explain
看下执行计划 - 数据库主从延迟问题考虑(必要时强制读主库)
- 避免在循环内做数据库的操作
SQL 规范
- 设计表的时候,所有表和字段都添加相应的注释
SQL
书写格式,关键字大小保持一致,使用缩进INSERT
语句标明对应的字段名称- 设计数据库表的时候,加上以下个字段(字段名可自定义):主键,
create*time
,update_time
,delete_flag
- 尽量把所有列定义为
NOT NULL
并提供默认值 - 所有表必须使用
Innodb
存储引擎 - 数据库和表的字符集尽量统一使用
utf8/utf8mb4
- 如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释
- 索引命名要规范,主键索引名为
pk*字段名
;唯一索引名为uk*字段名
;普通索引为idx_字段名
- 禁止使用外键,如果有外键完整性约束,由应用程序控制
索引规范
- 避免在更新比较频繁、区分度不高的列上单独建立索引
- 需要
JOIN
的字段,数据类型必须绝对一致; 多表关联查询时,保证被关联的字段需要有索引 - 建立联合索引时,必须将区分度更高的字段放在左边
- 在一个联合索引中,若第一列索引区分度等于 1,那么则不需要建立联合索引
- 利用覆盖索引来进行查询操作,避免回表
SQL 性能优化
- 写完
SQL
先explain
查看执行计划 - 写完
SQL
语句,检查where
,order by
,group by
后面的列,多表关联的列是否已加索引,优先考虑联合索引where
后面的字段,留意其数据类型的隐式转换 - 尽量使用
varchar
代替char
,如果存储的字符串长度几乎相等,则使用char
定长字符串类型 - 减少不必要的字段返回,如使用
select <具体字段> 代替 select *
- where 从句中不对列进行函数转换和表达式计算
- 如果修改/更新数据过多,考虑批量进行
- 在一些场景下,考虑使用
timestamp
代替datetime
- 不使用%开头的模糊查询
- 尽量避免在
WHERE
子句中使用or
作为连接条件 JOIN
的表不允许超过五个(一般不允许超过三个)- 不分页的集合查询应规定查询数量的上限,避免全量查询导致
OOM
SQL 后悔药
- 操作
delete
或者update
语句,加个limit
- 变更
SQL
操作先在测试环境执行,写明详细的操作步骤以及回滚方案,并在上生产前review
- 修改或删除重要数据前,要先备份,先备份,先备份
- 修改或者删除
SQL
,先写WHERE
查一下,确认后再补充delete
或update
SQL
命令行修改数据,养成begin + commit
事务的习惯