命名风格
1.不能以下划线或美元符号开头或结尾,不许使用中英文混合的模式命名.
2.必须使用驼峰命名,DO/BO/DTP/Vo/AO例外
3.常量名全部大写,单词用下划线隔开
4.抽象命名使用Abstract或Base开头,异常命名使用Exception结尾,测试类以Test结尾,枚举类名带上Enum后缀,枚举成员名称全部大写,单词间使用下划线隔开
5.POJO类中的布尔变量,不要加is,会导致部分框架的序列化错误
6.包名统一使用小写,点分割符之间只有一个自然语义的单词
7.杜绝不规范的缩写,比如Abstract写成Abs
8.接口类方法与数学不要加任何修饰符号,保持代码的简洁,不要在接口中定义变量
9.对于Service与DAO类,一定是接口,其实现类使用Impl后缀修饰
10.如果是形容能力的接口名,取对应的形容词做接口名-able,例如AbstractTranslator实现Translatable
11.Serveice/DAO层命名规约:
- 获取单个对象的方法用 get 做前缀。
- 获取多个对象的方法用 list 做前缀。
- 获取统计值的方法用 count 做前缀。
- 插入的方法用 save/insert 做前缀。
- 删除的方法用 remove/delete 做前缀。
- 修改的方法用 update 做前缀。
12.领域模型命名规则:
- 数据对象:xxxDO,xxx 即为数据表名。
- 数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
- 展示对象:xxxVO,xxx 一般为网页名称。
- POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
DTO:数据传输对象,用于前后端数据的传输,在后端它是java对象,在前端是ajax请求的数据体,一般用于表达一个模块的完整输出
VO:值对象,展示用的数据,用于展示给用户看的
PO:持久对象,表示数据库中的记录,一个PO数据结构对应着库中表的结构,一条记录就是一个PO对象
BO:BO是PO的组合,如果PO是一条交易记录,那么BO就是一个人全部的交易记录集合对象
DO:等同于PO
常量定义
1.不允许任何未经定义的常量直接出现在代码中
2.使用long或者Long进行初始赋值的时候要使用大写的L以免和数字1混淆
3.不要用一个常量类维护所有常量,要按照常量的功能进行归类,分开维护
4.如果一个变量的值只在一个范围内变化,且带有名称之外的属性,定义为枚举类
代码格式
1.if/for/while/switch/do等保留字与括号之间必须加空格
2.二目与三目运算符左右两边都需要加空格
3.使用4个空格缩进,而非tab字符
4.注释的双斜线与注释内容之间有且仅有一个空格
5.单行字符数不超过120个,超出时换行,从第二行开始对于第一行缩进4个空格,不要在括号中或者括号前换行
6.参数列表的参数间在,后加一个空格
OOP规约
1.避免通过类的对象引用访问静态变量与静态方法
2.覆盖方法必须加@Override注解,该注解可以准确判断是否覆盖成功,实现编译报错
3.尽量避免使用可变参数
4.接口过时的时候,添加@Deprecated注解,并说明采用的新接口是什么,不能使用过时的类与方法
5.Object的equals方法容易抛空指针异常,应使用常量或者确定有值的对象来调用
6.包装类之间值的比较必须使用equals
7.所有POJO类属性,RPC方法的返回值与参数必须使用包装数据类型.局部变量应使用基本数据类型
8.定义POJO类时不要设定任何属性的默认值,且必须写toString方法,如果是继承了另一个POJO类需要加super.toString
9.构造方法里静止加入任何业务逻辑,如果有初始化逻辑,应放在init方法中
10.使用索引访问String的split方法得到的数组时,需要对最后一个分隔符后有无内容做出检查
11.类中方法如果同名应该放在一起,其顺序应为:共有方法或保护方阿飞>私有方法>get/set方法
12.get/set方法中不要添加业务逻辑
13.循环体内,字符串的连接应使用StringBuilder的apped方法进行扩展
14.实现clone方法时,重写clone方法进行深拷贝
15.工具类中不允许有public或者default构造方法,protected,private修饰控制从严,如果是static成员变量必须考虑是否为final
集合处理
1.在自定义对象作为Map的键的时候,必须重写hashcode和equals,只要重写了equals就必须重写hashcode方法
2.arrayList的sublist结果不可以转化为arraylist,这是由于sublist的返回结果是arraylist中的一个内部类,该内部类是arraylist的一个视图,所有对子列表的操作最终会返回到原列表上.故若使用sublist,高度注意对原集合个数的修改,会导致字列表的遍历,增加,删除产生异常
3.集合转数组必须使用集合的toArray方法(T[] array)
4.使用工具类Array.asList()将数组转化为集合时,不能使用修改集合相关的方法
5.<? extends T>不能add,<? super T>不能get
6.不要在foreach循环里对元素进行集合的remove/add操作,如果需要,则使用Iterator方式,若并发,则需要对Iterator对象加锁
7. 在重写compare方法时,需要处理相等,大于和小于的情况
8. 集合初始化时需要指定集合初始值大小
9.使用entrySet遍历Map的KV,而不是KeySet的方式
10.避免使用List的contains方法进行遍历,对比与去重
并发处理
1.获取单例对象需要保证现场安全,其中的方法也要保证线程安全
2.创建线程时,要指定有意义的线程名称,方便出错时回溯
3.线程资源必须通过线程池提供,不允许自行显示的创建线程
4.创建线程池必须使用ThreadPoolExecutor的方式
5.SimpleDataFormat是线程不安全的类,一般不要定义为为static变量,若定义为static必须加锁,JDK8的应用使用Instant代替Date,LocalDataTime代替Calendar
6.尽可能的使锁的区域与对象控制的范围小
7.对多个资源加锁时,需要保持一致的加锁顺序
8.推荐使用countDownLatch进行异步转同步的操作
9.避免Random实例被多线程使用,会因为竞争同一seed导致性能下降
10.并发场景,通过双重检查锁方式,需要将目标声明为volatile
11.volatile用于解决一写多读的同步问题,多写情况下无法保证线程安全,可以使用原子类实现count++操作,LongAdder对象比AtomicLong性能更好
12.ThreadLocal无法解决共享对象的更新问题,使用时建议使用static修饰
控制语句
1.在一个switch块内,每个case要么通过break/return来终止,要么注释说明程序执行到哪个case位置,必须包含default语句并且放在最后,即使它什么代码都没有
2.避免使用单行代码的形式,即使只有一行代码
3.避免if else语句超过3层
4.不要在if语句内执行复杂的语句
5.以下情形考虑参数校验
- 调用频次低的方法。
- 执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参 数错误导致中间执行回退,或者错误,那得不偿失。
- 需要极高稳定性和可用性的方法。
- 对外提供的开放接口,不管是 RPC/API/HTTP 接口。
- 敏感权限入口。
以下情形不考虑参数校验
- 极有可能被循环调用的方法。但在方法说明里必须注明外部参数检查要求。
- 底层调用频度比较高的方法。毕竟是像纯净水过滤的最后一道,参数错误不太可能到底 层才会暴露问题。一般 DAO 层与 Service 层都在同一个应用中,部署在同一台服务器中,所 以 DAO 的参数校验,可以省略。
- 被声明成 private 只会被自己代码所调用的方法,如果能够确定调用方法的代码传入参 数已经做过检查或者肯定不会有问题,此时可以不校验参数
注释
1.类/类属性/类方法的注释必须使用Javadoc规范,即/**内容/
2.所有的抽象方法必须要用Javadoc注释,除了返回值,参数,异常说明外,还需要指出该方法做什么事情,实现何种功能
3.所有类都必须添加创建者与创建日期
4.方法内部单行注释,在被注释的语句上方另起一行,使用//,方法内部多行注释使用/*内容*/注释
5.所有枚举类型字段必须有注释,说明每个数据项的用途
6.除了专有名词可以使用英文以外,其他注释采用中文方式
7.注释中使用TODO标记目前还没有实现的功能,FIXME用于标记某代码是错误的
其他
1.后台输送给页面的遍历必须加$!{var}中间的感叹号,如果var不存在${}会直接出现在页面上
2.Math.random方法返回的是double类型,范围是[0,1),注意除0的异常,如果想获取整形随机数,应该使用Random对象的nextInt或nextLong方法
3.获取当前毫秒数应使用System.currentTimeMillis()而不是new Date()
4.数据结构的初始化最好指定大小,避免数据结构无限增长吃光内存