1 命名规约
- 命名符合本语言特性。比如在Java中,所有代码元素的命名均不能以下划线或美元符号开始或结束。
- 命名体现代码元素特征。
- 包名统一使用小写,点分隔符之间有且只有一个自然语义的英文单词。包名统一使用单数形式,但是类名如果有复数含义,则可以使用复数形式。
- 抽象类命名使用Abstract或Base开头;异常类命名用Exception结尾;测试类命名以它要测试的类名开始,以Test结尾。
- 类型与中括号紧挨相连来定义数组。
- 枚举类名带上Enum后缀,枚举类成员名称需要全部大写,单词间用下划线隔开。
- 命名最好望文知义。望文知义是在不需要额外解释的情况下,仅从名称上就能够理解某个词句的确切含义。在代码元素命名时做到望文知义,从而减少注释内容,达到自解释的目的。在实践中,望文知义的难度是最大的,就像给孩子起名一样需要反复斟酌。
1.1 常量
常量是在作用域内保持不变的值,一般用final关键字进行修饰,根据作用域分为全局常量、类内常量、局部常量。
- 全局常量:类的公开静态属性,使用
public static final
修饰 - 类内常量:类的私有静态属性,使用
private static final
修饰 - 局部常量:分为方法常量和参数常量,前者是在方法或代码块里定义的常量,后者是定义形式参数时,增加
final
标识,表示次此参数不能被修改。
全局常量和类内常量是最主要的常量表现形式,它们的命名方式比较特殊,采用字母全部大写、单词之间加下划线的方式。而局部常量采用小驼峰形式即可。实例代码如下:
public class Constant {
public static final String GLOBAL_CONSTANT = "shared in global";
private static final String CLASS_CONSTANT = "shared in class";
public void f(String a) {
final String methodConstant = "shared in method";
}
public void g(final int b) {
// 编译出错,不允许对常量参数进行重新赋值
b = 3;
}
}
枚举类型几乎是固定不变的全局常量,使用频率高,范围广,所以枚举常量都需要添加清晰的注释,比如业务相关信息或注意事项等。枚举类定义常量实例代码如下:
public enum CourseTypeEnum {
/**
* 允许官方和讲师创建和运营。
*/
VIDEO_COURSE(1, "录播课程"),
/**
* 只允许官方创建和运营。初始化必须设置合理的报名人数上限。
*/
LIVE_COURSE(2, "直播课程"),
/**
* 只允许官方创建和运营。
*/
OFFLINE_COURSE(3, "线下课程");
private int seq;
private String desc;
CourseTypeEnum(int seq, String desc) {
this.seq = seq;
this.desc = desc;
}
public int getSeq() {
return seq;
}
public String getDesc() {
return desc;
}
}
而我们把课程状态分为新课程、未审核课程、审核通过、审核未通过、已删除五种状态,考虑到后续课程状态还会再追加,并且状态没有扩展信息,所以用不能实例化的抽象类的全局常量来表示课程状态,实例代码如下:
public abstract class BaseCourseState {
public static final int NEW_COURSE = 1;
public static final int UNAUTHED_COURSE = 2;
public static final int PASSED_COURSE = 3;
public static final int NOT_PASSED_COURSE = 4;
public static final int DELETED_COURSE = 5;
}
1.2 变量
一般情况下,变量的命名需要满足小驼峰格式,命名体现业务含义即可。存在一种特殊情况,在定义成员变量时,特别是在POJO类中,针对布尔类型的变量,命名不要加is
前缀,否则部分框架解析会引起序列化错误。例如,定义标识是否删除的成员变量为Boolean isDeleted
,它的getter
方法也是isDeleted()
,框架在反向解析的时候误以为对应的属性名称是deleted
,导致获取不到属性,进而抛出异常。
2 代码展示风格
2.1 缩进、空格与空行
2.1.1 缩进
推荐采用4个空格缩进,禁止使用Tab键。
2.1.2 空格
- 任何二目、三目运算符的左右两边都必须加一个空格。
- 注释的双斜线与注释内容间有且仅有一个空格。
- 方法参数在定义和传入时,多个参数逗号后边必须加空格。
- 没有必要增加若干空格使变量的赋值等号与上一行对应位置的等号对齐。
- 如果是大括号内为空,简洁写成{}即可,大括号中间无需换行和空格。
- 左右小括号与括号内部的相邻字符之间不要出现空格。
- 左大括号前要加空格
2.1.3 空行
空行用来分隔功能相似、逻辑内聚、意思相近的代码片段,使程序布局更加清晰。在浏览代码时,空行可以起到自然停顿的作用,提升阅读代码的体验。在方法定义之后、属性定义与方法之间、不同逻辑、不同语义、不同业务的代码之间都需要通过空行来分隔。
2.2 换行与高度
2.2.1 换行
代码中需要限定每行的字符个数,以便适配显示器的宽度,以及方便CodeReview时进行diff比对。因此,约定单行字符数不超过120个,超出则需要换行。换行时遵循如下原则:
- 第二行相对第一行缩进4个空格,从第三行开始,不再继续缩进。
- 运算符与下文一起换行。
- 方法调用的点符号与下文一起换行。
- 方法调用中的多个参数需要换行时,在逗号后换行。
- 在括号前不要换行。
2.2.2 方法行数限制
单个方法的总行数不超过80行。详细的判定标准如下,除注释外,方法签名、左右大括号、空行、回车等字符的总行数不超过80行。
2.3 控制语句
- 在if、else、for、while、do-while等语句中必须使用大括号。
- 条件表达式中不允许有赋值操作,也不允许在判断表达式中出现复杂的逻辑组合。
- 多层嵌套不能超过三层。如果非得使用多层嵌套,请使用状态设计模式。对于超过3层的if-else逻辑代码,可以使用卫语句、策略模式、状态模式来实现。
- 避免采用取反逻辑运算符。
3 代码注释
3.1 注释三要素
- Nothing is strange.
- Less is more.
- Advance with the times.
3.2 注释格式
注释格式主要分为两种,一种是Javdoc规范,一种是简单注释。
3.2.1 Javadoc规范
类、类属性和类方法的注释必须遵循Javadoc规范,使用文档注释(/** */)的格式。这里特别强调对枚举类的注释是必须的,对枚举类注释的内容不仅限于解释属性值的含义,还包括注意事项、业务逻辑。如果新增或修改一个属性值,还要加上创建和修改时间,不可直接删除过时属性,需要标注为过时。
3.2.2 简单注释
包括单行注释和多行注释。特别强调此类注释不允许写在代码后方,必须写在代码上方。通常添加在非常必要的地方,如复杂算法或需要警示的特殊业务场景。