java的编码规范

命名规范

数组

类型与中括号紧挨相连来表示数组

正例:定义整形数组 int[] arrayDemo;

反例:在 main 参数中,使用 String args[]来定义。

POJO 类中布尔类型的变量

POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。

反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),RPC阿里巴巴 Java 开发手册

框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛

出异常。

涉及设计模式命名

如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式。

说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。

正例:public class OrderFactory;

public class LoginProxy;

public class ResourceObserver;

接口类中的方法和属性

接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。

正例:接口方法签名 void commit();

接口基础常量 String COMPANY = “alibaba”;

反例:接口方法定义 public abstract void f();

说明:JDK8 中接口允许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默

认实现。

接口和实现类的命名

1)对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部 的实现类用 Impl 的后缀与接口区别。

正例:CacheServiceImpl 实现 CacheService 接口。

2)如果是形容能力的接口名称,取对应的形容词为接口名(通常是–able 的形式)。

正例:AbstractTranslator 实现 Translatable 接口。

Enum

枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。

说明:枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有。

正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON。

常量定义

Long赋值

在 long 或者 Long 赋值时,数值后使用大写的 L,不能是小写的 l,小写容易跟数字 1 混淆,造成误解。

说明:Long a = 2l; 写的是数字的 21,还是 Long 型的 2?

常量类

不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。

说明:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解和维护。

正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts 下

enum

如果变量值仅在一个固定范围内变化用 enum 类型来定义。

说明:如果存在名称之外的延伸属性应使用 enum 类型,下面正例中的数字就是延伸信息,表

示一年中的第几个季节。

正例:

public enum SeasonEnum { 

SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4); 

private int seq; 

	SeasonEnum(int seq){ 

		this.seq = seq; 

	} 

} 

代码风格

单行字符数限制不超过 120 个

超出需要换行,换行时遵循如下原则:

1) 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。

2) 运算符与下文一起换行。

3) 方法调用的点符号与下文一起换行。

4) 方法调用中的多个参数需要换行时,在逗号后进行。

5) 在括号前不要换行,见反例。

正例:

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);  

单个方法的总行数不超过 80 行

说明:包括方法签名、结束右大括号、方法内代码、注释、空行、回车及任何不可见字符的总

行数不超过 80 行。

正例:代码逻辑分清红花和绿叶,个性和共性,绿叶逻辑单独出来成为额外方法,使主干代码

更加清晰;共性逻辑抽取成为共性方法,便于复用和维护。

OOP规约

Object 的 equals 方法

Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。

正例:“test”.equals(object);

反例:object.equals(“test”);

说明:推荐使用 java.util.Objects#equals(JDK7 引入的工具类)

equals 方法比较

所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。

说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在 IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,推荐使用 equals 方法进行判断。

POJO 类 toString 方法

POJO 类必须写 toString 方法。使用 IDE 中的工具:source> generate toString 时,如果继承了另一个 POJO 类,注意在前面加一下 super.toString。

说明:在方法执行抛出异常时,可以直接调用 POJO 的 toString()方法打印其属性值,便于排

查问题。

String 的 split 方法

使用索引访问用 String 的 split 方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛 IndexOutOfBoundsException 的风险。

说明:

String str = "a,b,c,,";  
String[] ary = str.split(",");  
// 预期大于 3,结果是 3 
System.out.println(ary.length); 

StringBuilder 的 append

循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。

说明:下例中,反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。

反例:

String str = "start";  
for (int i = 0; i < 100; i++) {  
str = str + "hello";  
} 

集合处理

subList

ArrayList的subList结果不可强转成ArrayList否则会抛出ClassCastException异常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。

说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。

在subList中高度注意对原集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。

Arrays.asList()

使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配器模式,只是转换接口,后台的数据仍是数组。

String[] str = new String[] { "you", "wu" }; 
List list = Arrays.asList(str); 

第一种情况:list.add("yangguanbao"); 运行时异常。

第二种情况:str[0] = "gujin"; 那么 list.get(0)也会随之修改。

泛型通配符

泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用 add 方法,而<? super T>不能使用 get 方法,作为接口调用赋值时易出错。

说明:扩展说一下 PECS(Producer Extends Consumer Super)原则:

第一、频繁往外读取内容的,适合用<? extends T>。

第二、经常往里插入的,适合用<? super T>。

foreach 的 remove/add 操作

不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。

正例:

List\<String> list = new ArrayList<>();  
list.add("1");  
list.add("2");  
Iterator\<String> iterator = list.iterator();  
while (iterator.hasNext()) {  
String item = iterator.next();  
	if (删除元素的条件) {  
		iterator.remove();  
	}  
} 

反例:

for (String item : list) {  
	if ("1".equals(item)) {  
		list.remove(item);  
	}  
} 

集合初始化时,指定集合初始值

说明:HashMap 使用 HashMap(int initialCapacity) 初始化。

正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。

反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被迫扩大,resize 需要重建 hash 表,严重影响性能。

使用 entrySet 遍历 Map 类集合 KV

说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出

key 所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效

率更高。如果是 JDK8,使用 Map.foreach 方法。

正例:values()返回的是 V 值集合,是一个 list 集合对象;keySet()返回的是 K 值集合,是一个 Set 集合对象;entrySet()返回的是 K-V 值组合集合。

Map 类集合 K/V 能不能存储 null 值的情况

集合类 Key Value Super 说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ITWGpxz3-1581644492704)(…/…/pic/1567475464289.png)]

反例: 由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,而事实上,

存储 null 值时会抛出 NPE 异常。

集合去重

利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的

contains 方法进行遍历、对比、去重操作。

集合有序性&稳定性

合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和

不稳定性(unorder)带来的负面影响。

说明:有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次

序是一定的。如:ArrayList 是 order/unsort;HashMap 是 unorder/unsort;TreeSet 是

order/sort。

控制语句

switch

在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使空代码。

条件判断中执行语句

除常用方法(如 getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。

说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?

正例:

// 伪代码如下 
final boolean existed = (file.open(fileName, "w") != null) && (...) || (...); 
if (existed) { 
...
}  

反例:

if ((file.open(fileName, "w") != null) && (...) || (...)) { 
... 
} 

循环性能

循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。

注释规范

头文件注释

/**
 * @ClassName
 * @Package
 * @Description
 * @Author
 * @Time
 *
 * @Updater
 * @Update Time
 * @Update Description
 * */

接口注释

/**
     * @Title
     * @Description
     * @param
     * @return
     * @throws
     * */

方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。

Enum

所有的枚举类型字段必须要有注释,说明每个数据项的用途。

注释代码

对于暂时被注释掉,后续可能恢复使用的代码片断,在注释代码上方,统一规定使用三个斜杠(///)来说明注释掉代码的理由。

发布了51 篇原创文章 · 获赞 0 · 访问量 744

猜你喜欢

转载自blog.csdn.net/lxy1740/article/details/104306977