图例:
强制
推荐
参考
严禁
不明觉厉
编码style
命名
_&
pinyin 中文
类UpperCamelCase;变量参数:lowerCamelCase; 常量:大写下划线;包名小写单数
Abstract~ Base~ ~Exception ~Test
private boolean isDeleted
OrderFactory;LoginProxy;ResourceObserver;设计模式
get list count save/insert remove/delete update
~DO ~DTO ~VO ~BO
代码格式
括号后换行
空格:保留字和括号间;二目三目运算符左右
四个空格缩进
注释//以后有一个空格
换行:/r/n的unix风格;120字符换行;.号换行;,号后换行;
text file encoding =UTF-8
单空格分隔
并发
获取单利对象需要保证线程安全,其中的方法也要保证线程安全;
创建线程时候指定有意义的线程名字
线程资源必须通过线程池提供
线程池不允许使用Executors创建,而是通过ThreadPoolExecutor方式
SimpleDateFormat线程不安全类;定义为static要加锁; 使用DataUtils工具类代替
锁的范围尽量小;尽量无锁数据结构;锁区块;锁方法体;锁对象;锁类;
多个资源,数据库表,对象同时加锁时,保持一致的加锁顺序;避免死锁;
加锁点:应用层加锁;缓存加锁;数据库层乐观锁;
多线程定时任务使用SchedualedExecutorService代替Timer
控制
switch语句case有break;default;
严禁单行语句;if (condition) stattements;
if if 优于 if else if
if 条件判断内不要执行复杂语句;将复杂的逻辑判断结果赋值给一个有意义的布尔变量名
变量定义声明,获取连接,不必要的try-catch移动到循环结果外面;
入参保护;参数校验
注释
javadoc注释:类,类属性,类方法
内部注释// 方法上方一行
类注释添加创建者和创建日期
其他
正则进行预编译,有效加快匹配速度;不在方法体内进行compile工作
后台输送给页面的变量必须加 $!{var} ——中间的感叹号。
Math.random()的取零异常;nextInt() nextLong()
Instant 类代替时间;System.currentTimeMillis();System.nanoTime();
暂时注释的代码用///写明注释的理由;
任何数据结构的构造和初始化,都应该指定大小;避免结构数据无限增长吃光内存;
oop规约
@override/@Deprecated
相同参数类型,相同业务含义才使用可变参数; 可变参数避免使用Object;避免使用可变参数;
POJO类属性必须使用包装数据类型
tostring();init();
增加属性不要修改serialVersionUID字段;避免反序列化失败; 不兼容升级的话,避免反序列化混乱,应该修改serialVersionUID
方法顺序:公用方法>私有方法>getter setter方法
setter中不增加业务逻辑
类和方法的访问控制从严
集合处理
hashCode和equals相伴相生
ArrayList.subList()返回的是ArrayList的内部类Sublist, 只是ArrayList的一个视图,对于SubList的操作会反映到源列表上;
集合转数组 toArray(T[] array)
数组转集合Arrays.asList()后,不能对集合进行修改
foreach循环内部进行元素的remove/add操作;使用Iterator操作;并发操作需加锁
Comparator接口实现必须考虑相等情况
集合初始化的时候指定初始大小;initialCapacity = (存储个数/负载因子)+1; 负载因子默认0.75;即超过75%容量值就进行一次扩容; HashMap默认初始大小16; ArrayList默认初始大小10; HashSet默认初始大小16;
Map的遍历使用entrySet遍历;Map.foreach方法
Map 类集合 K / V 能不能存储 null 值的情况
异常日志
异常处理
IOBE,NPE应通过预检查规避
异常不应来做流程控制
精确try-catch
捕获异常必须处理,否则往上抛
事务代码里头的try-catch手动回滚
try-catch-finally内关闭对象和资源;try-with-resources
finally内不能return
防止NPE是调用者的责任
抛出的异常应有业务含义;DAOException;ServiceException
日志
日志使用SLF4J中的API
日志文件保存时间》=15天;有些异常具备以周围频次发生的特点;
日志文件命名:appName_logType_logName.log
日志输出使用占位符或者条件输出!
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
日志应避免重复打印,additivity =false
日志记录内容:案发现场信息;堆栈信息
单元测试
单元测试原则AIR:Automatic;Independent;Repeatable
全程assert检查
单元测试之间不能相互调用
单元测试代码原则:BCDE:Border;Correct;Design;Error
数据库的查询更新删除操作,应使用程序插入或者导入数据方式准备数据;
数据库单元测试可以设定自动回滚机制 或者单元测试数据有明确前后缀标记;
对业务代码的要求: 1.简单构造方法 2.少依赖 3.少条件语句 4.少全局变量,静态方法
目录/src/test/java
新增代码及时增加单元测试;
测试目标: 语句覆盖率70%; 核心模块语句覆盖率100%;
安全规约
权限控制校验;
敏感数据脱敏
sql参数使用参数绑定 禁止字符串拼接sql访问数据库;
请求参数有效性验证: 1.pageSize 2.order by 3.重定向 4.反序列化注入 5.正则输入源拒绝服务ReDos
html页面要进行安全过滤,正确转义的用户数据;
csrf安全过滤
短信,邮件,电话,下单,支付: 防重限制 数量限制 疲劳度限制 验证码
用户生成内容的防刷,违禁词过滤
mysql数据库
建表
boolean值命名:is_xxx unsigned tinyint
表名,字段名小写字母数字(linux mysql 区分大小写) 表名使用单数名词 表名:业务名_表作业
保留字禁用
pk_xxx;uk_xxx;idx_xxx
小数类型使用decimal,禁止使用float,double
定长字符串 char
varchar 变长字符串,不预先分配存储空间;长度<5000 过长的使用text,分开成单独的表;
字段必备: id;必须为主键;unsigned bigint,单表时候自增,步长1 gmt_create,gmt_modified;date_time
单表行数超过500w,或单表容量超过2G,才进行分库分表;
合适的字符存储长度;unsigned tinyint;unsigned smallint;
索引
业务上具有唯一特性的字段,建立唯一索引;
禁止三表以上join join字段类型绝对一致
varchar字段建立索引指定索引长度;20长度就已经有90%的区分度了;
严禁左模糊匹配和全模糊匹配;
order by 利用索引的有序性; where a =? and b =? order by c; 索引: a _ b _ c
延迟关联或者子查询优化超多分页场景;
explain 级别限制range ref consts
建立组合索引,区分度高的前面;大小于号和等号混合时候,等号字段在前面;
SQL
count(*)会统计null的行
count(distinct col) 计算该列除了null之外的不重复行数
count(col)返回0;sum(col)返回null;注意NPE
count(0)直接返回;不执行后面的分页语句;
不能使用外键和级联;一切外键概念在应用层解决;
禁止使用存储过程;存储过程不好调试和移植
in 操作 尽量避免;集合数量不超过1000
ORM
查询字段明确,严禁*
配置隐射关系,不能省,字段级别
mybatis:#{} #param#;避免sql注入
ibatis自带的queryForList不推荐使用;
返回值类型不可以为hashMap和hashTable,返回值类型不可控制、
更新数据记录时候更新gmt_modified字段
更新操作;查询操作;字段粒度控制;越少越好;
@Transational不要滥用
工程结构
应用分层
分层领域模型