编程规约
- 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。 
- 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚. 
- POJO 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。 
- 接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁. 
- 不允许任何魔法值(即未经定义的常量)直接出现在代码中。 
- 所有的覆写方法,必须加@Override 注解。 
- 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。 
- setter 方法中,参数名称与类成员变量名称一致,this.成员名 = 参数名。在 getter/setter 方法中,不要增加业务逻辑,增加排查问题的难度。 
- 循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。 
- 对于Map,只要重写 equals,就必须重写 hashCode。 
- 如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals。 
- ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常. 
- 使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全 一样的数组,大小就是 list.size()。 
- 使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方 法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。 
- 泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用 add 方 法,而<? super T>不能使用 get 方法,做为接口调用赋值时易出错。 
- 说明:扩展说一下 PECS(Producer Extends Consumer Super)原则:1)频繁往外读取内容 的,适合用上界 Extends。2)经常往里插入的,适合用下界 Super。
- 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。 
- 集合初始化时,指定集合初始值大小。 
- 使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。 
- 获取单例对象需要保证线程安全,其中的方法也要保证线程安全。 
- SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类。 
- 高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能 锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。 
- 并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加 锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。 说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次 数不得小于 3 次。 
- 子线程抛出异常堆栈,不能在主线程 try-catch 到。 
- 避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一 
 seed 导致的性能下降。
- volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题, 但是如果多写,同样无法解决线程安全问题。 
- HashMap 在容量不够进行 resize 时由于高并发可能出现死链,导致 CPU 飙升,在 
 开发过程中可以使用其它数据结构或加锁来规避此风险。
- 表达异常的分支时,少用 if-else 方式,这种方式可以改写成:if return ; 
- 在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。不要在方法体内定义:Pattern pattern = Pattern.compile(规则); 
- 后台输送给页面的变量必须加$!{var}.如果 var=null 或者不存在,那么${var}会直接显示在页面上。 
29.注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x<1(能够 取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后 取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。
- 获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime(); 
- 异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。 
- 捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请 将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的 内容。 
- 不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。 
- 应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 
 SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
- 异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。 
数据库
- 任何字段如果为非负数,必须是 unsigned。 
- 表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。 
- 表名不使用复数名词。 
- 禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。 
- 主键索引名为 pk字段名;唯一索引名为 uk字段名;普通索引名则为 idx_字段名。 
- 小数类型为 decimal,禁止使用 float 和 double。 
- varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。 
- 表的命名最好是加上“业务名称_表的作用”。 
- 业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。 
- 超过三个表禁止 join。需要 join 的字段,数据类型必须绝对一致;多表关联查询 时,保证被关联的字段需要有索引。 
- 页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。 
- 如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合 索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort的情况,影响查询性能。 
- 建组合索引的时候,区分度最高的在最左边。 
- 防止因字段类型不同造成的隐式转换,导致索引失效。 
- 不要使用 count(列名)或 count(常量)来替代 count(),count()是 SQL92 定义的 标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。 
- count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。 
- 当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为 NULL,因此使用 sum()时需注意 NPE 问题。 
- 禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。 
- in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控 制在 1000 个之内。 
- POJO 类的布尔属性不能加 is,而数据库字段必须加 is_,要求在 resultMap 中进行 字段与属性之间的映射。 
- sql.xml 配置参数使用:#{},#param# 不要使用${} 此种方式容易出现 SQL 注入。 
- @Transactional 事务不要滥用。事务会影响数据库的 QPS,另外使用事务的地方需 要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。 
 
          