Google Java编码风格
前言
以下是摘自Hawstein的博客Google Java编程风格指南的学习笔记,下面仅列出我认为比较重要的知识点,没涉及到的可能是显而易见或约定俗成或者我觉得不重要的规范。使用良好的编码风格是coding最基本的素质之一。
1 源文件
1 源文件统一编码为UTF-8
2 特殊字符情形
a 除了行结束符外,空格是源文件唯一允许出现的空白字符,所有其他ASCII空白字符军需要进行转义,注意Tab符号一般表示制表符,不用于缩进。但是在很多编程场合下使用Tab的也大有人在。
我个人的认识是可能Tab在初次编写代码时确实比较好输入,而空格需要连续几次才行,但是后面如果有所更改或删除代码时(如多留空了),容易把Tab和空格弄糊涂,也可能与回退弄混,所以为了统一起见,默认可把Tab键设置成4或8个空格,Backspace键设置成2或4个空格,这样无论哪个键其实都是统一使用空格。Eclipse中貌似默认把Tab等价于8个空格,Backspace键设成4个空格。
b 对于具有特殊转义序列的任何字符(如\b
),使用它的转义序列而不是它的Unicode转义; 对于一些非ASCII字符,使用实际的Unicode字符还是使用等价的Unicode转义字符如(\u221e
),取决于对应代码的可读性。 不要害怕因为使用非ASCII字符而让你的代码可读性变差
3 源文件的组织结构
a 源文件按顺序的包括copyright或license(如有必要)、package语句、import语句、有且仅有一个顶级class,每个部分用一个空行隔开
b import语句规则
- 不换行,不要使用通配符,即不要出现
import java.util.*
- import语句可按如下分组,顺序导入语句,且每组结束后用一个空行分隔,组内不空行,按字典序排列
顺序如下:
- 所有的静态导入成一组
com.google
导入(针对引用的源文件在此包下)- 第三方的包(每个顶级包作为一组,按字典序,如
com
,junit
,org
) java
导入javax
导入
2 格式
1 在非空块和块状结构时(如类,方法的主体,条件语句或循环语句),要使用大括号,并且遵循K&R风格
int hello() { //左大括号之前不换行,之后换行
//函数体中若是语句等的终止,右大括号后换行,否则不换行
if (xxx) {
//do something
}
if (xxx) {
//do something
} else {
//do other thing
}
} //右大括号前换行
2 应用水平空白的情形
- 分隔任何保留字与紧随其后的左括号,如
if
,for
,catch
等(这个我平时用的不多) - 分隔任何保留字与其前面的右大括号,如
else
- 在任何大左括号前,除了
@AnnotationXXX ({a,b})
等不使用空格 - 在任何二元或三元运算符两侧都要使用空格,也适用于类运算符,如
<T extends Foo & Bar>
- 在
, : ; )
后都应添加空格 - 不建议让注释水平对齐,修改内容后就使得对齐代码错位,不方便维护,所以建议一开始就无需对齐
**3 每次只声明一个变量,不要使用组合声明int a,b
**
4 数组初始化可写成块状结构
new int[] {
0, 1, 2, 3
}
new int[] {
0, 1
2, 3
}
5 在switch语句中如果程序将继续执行到下一个语句组,需要添加能够表达该意思的注释,该特殊的注释无需在最后default:
中出现并且默认情况必须要写出来,即使什么代码不包括
switch (intput) {
case 1:
case 2:
xxx;
//fall through
case 3:
xxx;
break;
default:
xxx;
}
6 注解独占一行,用于类,方法构造函数中
@Override
@Nullable
public String get() {
...
}
//只要是合法的,重写@Override的注解能用则用
//例外: 单个注解可和函数签名第一行出现在同一行中
@Override public int hashCode() {
...
}
//用于字段的注解随文档块出现,也可允许出现在同一行
@XXX @YYY DataLoader loader;
7 注释风格,建议统一使用Javadoc方式
/**
* 用于描述方法或类
*/
/** 单行形式,一般用于描述类的变量 */
// 用于描述方法内部的单个语句
Javadoc有一些约定俗称的标记,例如
- 除首段落,每个段落第一个单词前都有标签
<p>
,并且它和第一个单词没有空格 - Javadoc标记按如下顺序出现:
@param
,@return
,@throws
,@deprecated
,且描述都不能为空 - 一个单行的简要片段,应该写成
/** get xxx*/
,而不是/** @return xxx*/
例如JDK库中的StringBuilder类描述
/**
* A mutable sequence of characters. This class provides an API compatible
* with <code>StringBuffer</code>, but with no guarantee of synchronization.
* This class is designed for use as a drop-in replacement for
* <code>StringBuffer</code> in places where the string buffer was being
* used by a single thread (as is generally the case). Where possible,
* it is recommended that this class be used in preference to
* <code>StringBuffer</code> as it will be faster under most implementations.
*
* <p>
* For example, if <code>z</code> refers to a string builder object
* whose current contents are "<code>start</code>", then
* the method call <code>z.append("le")</code> would cause the string
* builder to contain "<code>startle</code>", whereas
* <code>z.insert(4, "le")</code> would alter the string builder to
* contain "<code>starlet</code>".
*
* @author Michael McCloskey
* @see java.lang.StringBuffer
* @see java.lang.String
* @since 1.5
*/
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the <code>capacity</code> argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the <code>capacity</code>
* argument is less than <code>0</code>.
*/
public StringBuilder(int capacity) {
super(capacity);
}
8 捕获的异常不能忽视,必须响应。如果catch块确实不需要回应,必须要加注释以说明;另外如果能确保测试的方法会抛出一个期望的异常,就没必要加注释
try {
xxx;
fail();
} catch (NoSuchElementException expected) {
}
3 命名
标识符只能使用ASCII字母和数字,即每个有效的标识符名称都匹配正则表达式\W+
。注意在Google其他编程语言风格中使用的特殊前缀,如mName
,s_name
,name_
等均不能在Java中使用。
驼峰式命名法分为UpperCamelCase和lowerCamerCase。这个英文写法就说明了命名的规则,按单词划分根据命名规则决定每个单词首字母的大小写,再连接起来形成一个标识符
1 如果类和成员的修饰符都存在,按Java语言规范推荐的顺序出现
public protected private abstract static final transient volatile synchronized
native strictfp
2 包名全部小写,连续的单词直接连接起来,且不使用下划线
3 常量命名模式为CONSTANT_CASE
,全部字母大写,用下划线分割单词
每个常量都是一个静态final字段但并非所有这样的字段都是常量。决定是否常量是取决于它的实际情况,如果永远不打算改变对象,一直不变则设为常量。如下面例子
//Constants
static final int NUMBER = 5;
static final Joiner COMMA_JOINER = Joiner.on(','); //immutable Joiner
static final Immutable<String> NAMES = ImmutableList.of("Ed", "Ann");
enum SomeEnum { ENUM_CONS }
static final SomeType[] EMPTY_ARRAY = []; //不变类
//Not constants
static String nonfinal = "non-final";
final String nonstatic = "non-static";
static final Set<String> mutableCollection = new HashSet<String>();
static final String[] nonEmptyArray = {"these", "can", "change"};
static final ImmutableSet<XXX> mutableElements = ImmutableSet.of(mutable);
static final Logger logger = Logger.getLogger(MyClass.getName());
4 类名统一使用UpperCamelCase
风格编写,通常是名词或名词短语,接口有可能是形容词或形容词短语。测试类命令以它要测试的类名称开始,以Test
结束
5 方法名、非常量字段名、参数名和局部变量名都是lowerCamelCase
风格。方法名要求是动词或动词短语,参数和局部变量名尽量避免使用单字符命名,除了循环变量和临时变量