一:命名风格
- 代码中代码严禁拼音和英文混合的方式,更不允许直接用纯中文标识
- 在POJO类中布尔类型的变量不要加is前缀。例如isDeleted变量,RPC框架在反向解析的时候以为属性是delect
- 禁止POJO类属性xxx同时出现isXxx()和getXxx()方法。因为框架在属性方法提取时并不能保证哪个方法被优先调用得到
- 接口类中的方法和属性不要添加任何修饰符号,保持代码的间接性
- 接口方法签名:void commit();
- 接口基础常量:String COMPANY = “dafang”;
- 代码格式
public static void main(String[] args) {
// 缩进4个空格(注释//后必须加一个空格)
String say = "hello";
// 运算的左右必须有一个空格
int flag = 0;
// 关键词if与括号之间必须有1个空格,括号内的f与左括号、0与右括号之间不需要空格
if (flag == 0) {
System.out.println(say);
}
// 左大括号前加空格且不换行;左大括号后换行
if (flag == 1) {
System.out.println("word");
// 左大括号前换行,右大括号后有else,不用换行
}else {
System.out.println("ok");
// 在右大括号后直接结束,则必须换行
}
}
- 所有的覆写方法,必须加@Override
- 基本数据和包装数据类型的使用标准
- 所有的POJO类属性必须使用包装数据类型
- RPC(Remote Promote Call)方法的返回值和参数必须使用包装数据类型
- 所有的局部变量使用基本数据类型
说明: 数据库的查询结果可能是null,因为自动拆箱,所有用基本数据类型接收有NPE(NullPointerException)
- 构造方法里禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中
- 在setter/getter方法中,参数名称和类成员变量名称一致。不要增加业务逻辑,否则会增加排查问题的难度
错误示例public Integer getData() { if (condition) { return this.data + 100; }else { return this.data - 100; } }
- 集合操作中需要注意的几点
- 在foreach循环里进行元素的remove/add操作,会报ClassCastException
- 使用迭代器Iterator遍历时使用集合自带的自带的remove()会报ClassCastException,可以使用迭代器自带的remove() 案例
- jdk7后对于数据排序需要返回等于0的情况,之后版本排序可以看之前的博客java8让排序更加优雅
- 集合初始化时需要给定初始值大小initiaCapacity = (需要存储的元素个数/负载因子)+1
假设HashMap 需要放置1024个元素,因为没有设置初始大小。元素的增加导致容量被迫扩大7次,resize需要重建hash表,这严重影响性能
二:控制语句
-
在switch块中每个case要么通过break/return等来终止,要么注释说明程序将执行到哪一个case为止。每个块内必须包含一个default,哪怕它什么代码也没有。除非使用jdk12
//新特性 switch (day) { case MONDAY, FRIDAY, SUNDAY -> System.out.println(6); case TUESDAY -> System.out.println(7); case THURSDAY, SATURDAY -> System.out.println(8); case WEDNESDAY -> System.out.println(9); } //以及在表达式返回值 int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; };
-
在if / else / for /while /do语句中必须使用大括号,哪怕只有一行代码
-
在高并发场景中,避免使用“等于”来作为中断条件。例如判断奖品等于0终止发放,但是由于并发处理会导致数量瞬间变为负数,这样的话活动就无法截至
-
不要在条件判断中执行其他复杂的语句,可以将复杂的逻辑判断的结果赋值给一个有意义的布尔变量名,可以提高可读性
// 正例 final boolean existed = (file.open(name,"w")!=null) && (...) || (...); if (existed) { } // 反例 if ( (file.open(name,"w")!=null) && (...) || (...)) { }
-
避免采用取反逻辑运算符
说明 取反逻辑不利于快速理解,并且去反逻辑写法必然存在对应的正向逻辑写法
正例:使用if (x < 628)来表达x小于628
反例:使用if (!(x >= 628))来表达x小于628
三:控制语句
- 线程资源必须通过线程池提供,不允许在应用中自行的显示创建线程
说明 使用线程池的好处减少在创建和销毁线程上所消耗的时间及系统资源,解决资源不足的问题。如果不使用线程池,可能会造成大量同类线程二导致消耗完内存或者“过度切换”的问题
- 必须回收自定义的ThreadLocal变量,尤其在线程池场景下
- 在高并发场景中,同步调用应该去考量锁的性能损耗。能用无锁结构就不要用锁。能用锁区块,就不要用整个方法体。能用对象锁,就不要用类锁。使加锁的代码块工作量尽可能小
- HashMap在容量不够进行resize时,由于高并发可能出现死锁,导致cpu占用率飙升,在开发中可以使用其他数据结构(几种线程安全的map)或者加锁来规避此风险。
四:注释规约
- 类、类属性、类方法的注释必须使用Javadoc规范,使用/*内容/格式,不得使用//xxx方式
- 所有的抽象方法(包括接口中的方法)必须使用javadoc注释,除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现了什么功能
说明 对子类的实现要求,或者调用注意事项,轻一并说明
- 所有的类必须添加创建者和创建时间
- 如果使用的是ecplise的话需要注意,每次格式化的时候。可能会将注释代码也格式化,为了不改变注释风格需要设置Preferences->java->Code style->Formatter点击new。然后点击Edit->Comments再将下面两个选框√去掉
- 在修改代码的同时要对注释进行相应的修改,尤其是参数、返回值、异常、核心的逻辑
说明 代码与注释更新不同步,就像网络与导航软件更新不同步。如果导航软件更新严重滞后,就失去了导航的意义
- 及时清理不在使用的代码段或配置信息。避免程序过度臃肿,代码冗余。
- 谨慎注释掉代码,要在上方详细说明,而不是简单地注释掉,如果无用则删除
- 如果后续要恢复此段逻辑代码,没有备注信息,难以知晓注释动机。无用则删掉,如果要查阅历史代码,查看代码仓库(svn git)看历史版本即可
- 对于暂时注释掉后续会恢复使用的代码片段,在注释代码上方,统一规定使用三个斜杠///来说明注释代码的理由