记录一下自己在平时写代码中没有注意到的规范
命名规约
1 【强制】 POJO 类中布尔类型的变量,都不要加 is ,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型 boolean isSuccess
; 的属性,它的方法也是 isSuccess()
, RPC框架在反向解析的时候,“以为”对应的属性名称是 success
,导致属性获取不到,进而抛出异常。
2 【推荐】接口类中的方法和属性不要加任何修饰符号 (public 也不要加 ) ,保持代码的简洁性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是与接口方法相关,并且是整个应用的基础常量。
- 正例:接口方法签名:
void f();
接口基础常量表示:String COMPANY = "alibaba" ;
- 反例:接口方法定义:
public abstract void f();
- 说明: JDK 8 中接口允许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默认实现。
3 【参考】各层命名规约:
- Service / DAO 层方法命名规约
1 ) 获取单个对象的方法用 get 做前缀。
2 ) 获取多个对象的方法用 list 做前缀。
3 ) 获取统计值的方法用 count 做前缀。
4 ) 插入的方法用 save( 推荐 ) 或 insert 做前缀。
5 ) 删除的方法用 remove( 推荐 ) 或 delete 做前缀。
6 ) 修改的方法用 update 做前缀。
常量定义
-
【强制】不能使用magic number。
-
【强制】 long 或者 Long 初始赋值时,必须使用大写的 L ,不能是小写的 l ,小写容易跟数字
-
【推荐】不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。如:缓存相关的常量放在类: CacheConsts 下 ; 系统配置相关的常量放在类: ConfigConsts 下。
-
【推荐】如果变量值仅在一个范围内变化用 Enum 类。如果还带有名称之外的延伸属性,必须使用 Enum 类,下面正例中的数字就是延伸信息,表示星期几。
- 正例: public Enum { MONDAY(1), TUESDAY(2) , WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6) , SUNDAY(7); }
格式约定
- 【强制】缩进采用 4 个空格,禁止使用 tab 字符。
- 【强制】 左括号和后一个字符之间不出现空格 ; 同样,右括号和前一个字符之间也不出现空格。
- 【强制】 if / for / while / switch / do 等保留字与左右括号之间都必须加空格。
- 【强制】任何运算符左右必须加一个空格。正例:
public static void main(String args[]) { // 缩进 4 个空格 String say = "hello"; // 运算符的左右必须有一个空格 int flag = 0; // 关键词 if 与括号之间必须有一个空格,括号内的 f 与左括号,0 与右括号不需要空格 if (flag == 0) { System.out.println(say); } // 左大括号前加空格且不换行;左大括号后换行 if (flag == 1) { System.out.println("world"); // 右大括号前换行,右大括号后有 else,不用换行 } else { System.out.println("ok"); // 在右大括号后直接结束,则必须换行 } }
- 【强制】单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:
- 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。
- 运算符与下文一起换行。
- 方法调用的点符号与下文一起换行。
- 在多个参数超长,逗号后进行换行。
- 在括号前不要换行,见反例。
- 正例:
StringBuffer sb = new StringBuffer(); //超过 120 个字符的情况下,换行缩进 4 个空格,并且方法前的点符号一起换行 sb.append("zi").append("xin")... .append("huang")... .append("huang")... .append("huang");
- 反例:
StringBuffer sb = new StringBuffer(); //超过 120 个字符的情况下,不要在括号前换行 sb.append("zi").append("xin")...append ("huang"); //参数很多的方法调用可能超过 120 个字符,不要在逗号前换行 method(args1, args2, args3, ... , argsX);
- 正例:
- 【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
- 正例:下例中实参的” a “,后边必须要有一个空格。
method("a", "b", "c");
- 正例:下例中实参的” a “,后边必须要有一个空格。
OOP 规约
- 【推荐】 setter 方法中,参数名称与类成员变量名称一致, this.成员名=参数名。在getter/setter 方法中,尽量不要增加业务逻辑,增加排查问题的难度。
- 反例
public Integer getData(){ if(true) { return data + 100; } else { return data - 100; } }
- 反例
- 【推荐】循环体内,字符串的联接方式,使用 StringBuilder 的 append 方法进行扩展。
- 反例:
String str = "start"; for(int i=0; i<100; i++){ str = str + "hello"; //性能问题,内存浪费 }
- 反例:
- 【推荐】 final 可提高程序响应效率,声明成 final 的情况:
- 不需要重新赋值的变量,包括类属性、局部变量。
- 对象参数前加 final ,表示不允许修改引用的指向。
- 类方法确定不允许被重写。
-
【推荐】慎用 Object 的 clone 方法来拷贝对象。
- 说明:对象的 clone 方法默认是浅拷贝,若想实现深拷贝需要重写 clone 方法实现属性对象的拷贝。
集合处理
- 【强制】关于 hashCode 和 equals 的处理,遵循如下规则:
1) 只要重写 equals ,就必须重写 hashCode 。 详解: http://blog.csdn.net/jiangwei0910410003/article/details/22739953,简单来说就是为了保证objectA.equals(objectB) 能得到 objectA.hashCode() == objectB.hashCode();
2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法。
3) 如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals 。 map也是使用equals和hashCode来定位元素的如果hashCode都不相等就没必要你比较equals
正例: String 重写了 hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象作为map的key 来使用。 - 【强制】 ArrayList 的 subList (慎用 )结果不可强转成 ArrayList ,否则会抛出 ClassCastException异常: java.util.RandomAccessSubList cannot be cast to java.util.ArrayList ;
说明: subList 返回的是 ArrayList 的内部类 SubList ,并不是 ArrayList ,而是ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。 - 【强制】在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均产生 ConcurrentModificationException 异常。 http://blog.csdn.net/kkgbn/article/details/71169680
-
【推荐】高度注意 Map 类集合 K / V 能不能存储 null 值的情况,如下表格:
集合类KeyValueSuper说明Hashtable 不允许为 null 不允许为 null Dictionary 线程安全 ConcurrentHashMap 不允许为 null 不允许为 null AbstractMap 分段锁技术 TreeMap 不允许为 null 允许为 null AbstractMap 线程不安全 HashMap 允许为 null 允许为 null AbstractMap 线程不安全
反例: 由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,注意存储 null 值时会抛出 NPE 异常。
控制语句
- 【强制】在一个 switch 块内,每个 case 要么通过 break / return 等来终止,要么注释说明程序将继续执行到哪一个case为止 ; 在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。
- 【强制】在 if / else / for / while / do 语句中必须使用大括号,即使只有一行代码,避免使用下面的形式: if (condition) statements;
- 【推荐】推荐尽量少用 else , if - else 的方式可以改写成:
- 说明:如果非得使用 if()...else if()...else... 方式表达逻辑,【强制】请勿超过 3 层,超过请使用状态设计模式。
- 正例:逻辑上超过 3 层的 if-else 代码可以使用卫语句,或者状态模式来实现。
if(condition){ ... return obj; } // 接着写 else 的业务逻辑代码;
- if(IsWorkDay())
- {
- printf("Error,is work day");
- }
- else
- {
- if(IsWorkTime())
- {
- printf("Error ,is work time");
- }
- else
- {
- rest();
- }
- }
转变为
- if(IsWorkDay())
- {
- printf("Error,is work day");
- return;
- }
- if(IsWorkTime())
- {
- printf("Error,is work time");
- return ;
- }
- rest();