Googlejava编程技术规范
不遵循规范的程序猿,不是好的coder。
学习java有⼀段时间了,⼀直想java编程技术规范来学习⼀下,幸⽽⽹络资源丰富,各路玩家乐于分享,省去了好多⿇烦,姑且算站在⽹友的肩上,砥砺前⾏。
/*********  原⽂作者&链接***********/
作者:Hawstein
出处:
声明:本⽂采⽤以下协议进⾏授权:,转载请注明作者及出处。
⽬录
1. 前⾔
2. 源⽂件基础
3. 源⽂件结构
4. 格式
5. 命名约定
6. 编程实践
7. Javadoc
8. 后记
这份⽂档是Google Java编程风格规范的完整定义。当且仅当⼀个Java源⽂件符合此⽂档中的规则,我们才认为它符合Google的Java编程风格。
与其它的编程风格指南⼀样,这⾥所讨论的不仅仅是编码格式美不美观的问题,同时也讨论⼀些约定及编码标准。然⽽,这份⽂档主要侧重于我们所普遍遵循的规则,对于那些不是明确强制要求的,我们尽量避免提供意见。
1.1 术语说明
在本⽂档中,除⾮另有说明:
1. 术语class可表⽰⼀个普通类,枚举类,接⼝或是annotation类型(@interface)
2. 术语comment只⽤来指代实现的注释(implementation comments),我们不使⽤“documentation comments”⼀词,⽽是⽤Javadoc。
其他的术语说明会偶尔在后⾯的⽂档出现。
1.2 指南说明
本⽂档中的⽰例代码并不作为规范。也就是说,虽然⽰例代码是遵循Google编程风格,但并不意味着这是展现这些代码的唯⼀⽅式。⽰例中的格式选择不应该被强制定为规则。
2.1 ⽂件名
源⽂件以其最顶层的类名来命名,⼤⼩写敏感,⽂件扩展名为.java。
2.2 ⽂件编码:UTF-8
源⽂件编码格式为UTF-8。
2.3 特殊字符
2.3.1 空⽩字符
除了⾏结束符序列,ASCII⽔平空格字符(0x20,即空格)是源⽂件中唯⼀允许出现的空⽩字符,这意味着:
1. 所有其它字符串中的空⽩字符都要进⾏转义。
2. 制表符不⽤于缩进。
2.3.2 特殊转义序列
对于具有特殊的任何字符(\b, \t, \n, \f, \r, \“, \‘及\),我们使⽤它的转义序列,⽽不是相应的⼋进制(⽐如\012)或Unicode(⽐如\u000a)转义。
2.3.3 ⾮ASCII字符
对于剩余的⾮ASCII字符,是使⽤实际的Unicode字符(⽐如∞),还是使⽤等价的Unicode转义符(⽐如\u221e),取决于哪个能让代码更易于阅读和理解。
Tip: 在使⽤Unicode转义符或是⼀些实际的Unicode字符时,建议做些注释给出解释,这有助于别⼈阅读和理解。
例如:
String unitAbbrev = "µs";                                | 赞,即使没有注释也⾮常清晰
String unitAbbrev = "\u03bcs"; // "µs"                    | 允许,但没有理由要这样做
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"    | 允许,但这样做显得笨拙还容易出错
String unitAbbrev = "\u03bcs";                            | 很糟,读者根本看不出这是什么
return '\ufeff' + content; // byte order mark            | Good,对于⾮打印字符,使⽤转义,并在必要时写上注释
Tip: 永远不要由于害怕某些程序可能⽆法正确处理⾮ASCII字符⽽让你的代码可读性变差。当程序⽆法正确处理⾮ASCII字符时,它⾃然⽆法正确运⾏,你就会去fix这些问题的了。(⾔下之意就是⼤胆去⽤⾮ASCII字符,如果真的有需要的话)
⼀个源⽂件包含(按顺序地):
1. 许可证或版权信息(如有需要)
2. package语句
3. import语句
4. ⼀个顶级类(只有⼀个)
以上每个部分之间⽤⼀个空⾏隔开。
3.1 许可证或版权信息
如果⼀个⽂件包含许可证或版权信息,那么它应当被放在⽂件最前⾯。
3.2 package语句
package语句不换⾏,列限制(4.4节)并不适⽤于package语句。(即package语句写在⼀⾏⾥)
3.3 import语句
3.3.1 import不要使⽤通配符
即,不要出现类似这样的import语句:import java.util.*;
3.3.2 不要换⾏
import语句不换⾏,列限制(4.4节)并不适⽤于import语句。(每个import语句独⽴成⾏)
3.3.3 顺序和间距
import语句可分为以下⼏组,按照这个顺序,每组由⼀个空⾏分隔:
1. 所有的静态导⼊独⽴成组
2. le imports(仅当这个源⽂件是在le包下)
3. 第三⽅的包。每个顶级包为⼀组,字典序。例如:android, com, junit, org, sun
4. java imports
5. javax imports
组内不空⾏,按字典序排列。
3.4 类声明
3.4.1 只有⼀个顶级类声明
每个顶级类都在⼀个与它同名的源⽂件中(当然,还包含.java后缀)。
例外:package-info.java,该⽂件中可没有package-info类。
3.4.2 类成员顺序
类的成员顺序对易学性有很⼤的影响,但这也不存在唯⼀的通⽤法则。不同的类对成员的排序可能是不同的。最重要的⼀点,每个类应该以某种逻辑去排序它的成员,维护者应该要能解释这种排序逻辑。⽐如,新的⽅法不能总是习惯性地添加到类的结尾,因为这样就是按时间顺序⽽⾮某种逻辑来排序的。
3.4.2.1 重载:永不分离
当⼀个类有多个构造函数,或是多个同名⽅法,这些函数/⽅法应该按顺序出现在⼀起,中间不要放进其它函数/⽅法。
术语说明:块状结构(block-like construct)指的是⼀个类,⽅法或构造函数的主体。需要注意的是,数组初始化中的初始值可被选择性地视为块状结构(4.8.3.1节)。
4.1 ⼤括号
4.1.1 使⽤⼤括号(即使是可选的)
⼤括号与if, else, for, do, while语句⼀起使⽤,即使只有⼀条语句(或是空),也应该把⼤括号写上。
4.1.2 ⾮空块:K & R 风格
对于⾮空块和块状结构,⼤括号遵循Kernighan和Ritchie风格 ():
左⼤括号前不换⾏
左⼤括号后换⾏
右⼤括号前换⾏
如果右⼤括号是⼀个语句、函数体或类的终⽌,则右⼤括号后换⾏; 否则不换⾏。例如,如果右⼤括号后⾯是else或逗号,则不换⾏。
⽰例:
return new MyClass() {
@Override public void method() {
if (condition()) {
try {
something();
} catch (ProblemException e) {
recover();
}
}
}
};
4.8.1节给出了enum类的⼀些例外。
4.1.3 空块:可以⽤简洁版本
⼀个空的块状结构⾥什么也不包含,⼤括号可以简洁地写成{},不需要换⾏。例外:如果它是⼀个多块语句的⼀部分(if/else 或 try/catch/finally) ,即使⼤括号内没内容,右⼤括号也要换⾏。
⽰例:
void doNothing() {}
4.2 块缩进:2个空格
每当开始⼀个新的块,缩进增加2个空格,当块结束时,缩进返回先前的缩进级别。缩进级别适⽤于代码和注释。(见4.1.2节中的代码⽰例)
4.3 ⼀⾏⼀个语句
每个语句后要换⾏。
4.4 列限制:80或100
⼀个项⽬可以选择⼀⾏80个字符或100个字符的列限制,除了下述例外,任何⼀⾏如果超过这个字符数限制,必须⾃动换⾏。
例外:
1. 不可能满⾜列限制的⾏(例如,Javadoc中的⼀个长URL,或是⼀个长的JSNI⽅法参考)。
2. package和import语句(见
3.2节和3.3节)。
3. 注释中那些可能被剪切并粘贴到shell中的命令⾏。
4.5 ⾃动换⾏
术语说明:⼀般情况下,⼀⾏长代码为了避免超出列限制(80或100个字符)⽽被分为多⾏,我们称之为⾃动换⾏(line-wrapping)。
我们并没有全⾯,确定性的准则来决定在每⼀种情况下如何⾃动换⾏。很多时候,对于同⼀段代码会有好⼏种有效的⾃动换⾏⽅式。
Tip: 提取⽅法或局部变量可以在不换⾏的情况下解决代码过长的问题(是合理缩短命名长度吧)
4.5.1 从哪⾥断开
⾃动换⾏的基本准则是:更倾向于在更⾼的语法级别处断开。
1. 如果在⾮赋值运算符处断开,那么在该符号前断开(⽐如+,它将位于下⼀⾏)。注意:这⼀点与Google其它语⾔的编程风格不同(如C++和JavaScript)。这条规则也适⽤
于以下“类运算符”符号:点分隔符(.),类型界限中的&(<T extends Foo & Bar>),catch块中的管道符号(catch (FooException | BarException e)
2. 如果在赋值运算符处断开,通常的做法是在该符号后断开(⽐如=,它与前⾯的内容留在同⼀⾏)。这条规则也适⽤于foreach语句中的分号。
3. ⽅法名或构造函数名与左括号留在同⼀⾏。
4. 逗号(,)与其前⾯的内容留在同⼀⾏。
4.5.2 ⾃动换⾏时缩进⾄少+4个空格
⾃动换⾏时,第⼀⾏后的每⼀⾏⾄少⽐第⼀⾏多缩进4个空格(注意:制表符不⽤于缩进。见2.3.1节)。
当存在连续⾃动换⾏时,缩进可能会多缩进不只4个空格(语法元素存在多级时)。⼀般⽽⾔,两个连续⾏使⽤相同的缩进当且仅当它们开始于同级语法元素。
第4.6.3⽔平对齐⼀节中指出,不⿎励使⽤可变数⽬的空格来对齐前⾯⾏的符号。
4.6 空⽩
4.6.1 垂直空⽩
以下情况需要使⽤⼀个空⾏:
1. 类内连续的成员之间:字段,构造函数,⽅法,嵌套类,静态初始化块,实例初始化块。
例外:两个连续字段之间的空⾏是可选的,⽤于字段的空⾏主要⽤来对字段进⾏逻辑分组。
2. 在函数体内,语句的逻辑分组间使⽤空⾏。
3. 类内的第⼀个成员前或最后⼀个成员后的空⾏是可选的(既不⿎励也不反对这样做,视个⼈喜好⽽定)。
4. 要满⾜本⽂档中其他节的空⾏要求(⽐如3.3节:import语句)
多个连续的空⾏是允许的,但没有必要这样做(我们也不⿎励这样做)。
4.6.2 ⽔平空⽩
除了语⾔需求和其它规则,并且除了⽂字,注释和Javadoc⽤到单个空格,单个ASCII空格也出现在以下⼏个地⽅:
1. 分隔任何保留字与紧随其后的左括号(()(如if, for catch等)。
2. 分隔任何保留字与其前⾯的右⼤括号(})(如else, catch)。
3. 在任何左⼤括号前({),两个例外:
@SomeAnnotation({a, b})(不使⽤空格)。
String[][] x = foo;(⼤括号间没有空格,见下⾯的Note)。
4. 在任何⼆元或三元运算符的两侧。这也适⽤于以下“类运算符”符号:
类型界限中的&(<T extends Foo & Bar>)。
块中的管道符号(catch (FooException | BarException e)。
语句中的分号。java做什么的
5. ())后
6. 如果在⼀条语句后做注释,则双斜杠(//)两边都要空格。这⾥可以允许多个空格,但没有必要。
7. 类型和变量之间:List list。
8. 数组初始化中,⼤括号内的空格是可选的,即new int[] {5, 6}和new int[] { 5, 6 }都是可以的。
Note:这个规则并不要求或禁⽌⼀⾏的开关或结尾需要额外的空格,只对内部空格做要求。
4.6.3 ⽔平对齐:不做要求
术语说明:⽔平对齐指的是通过增加可变数量的空格来使某⼀⾏的字符与上⼀⾏的相应字符对齐。
这是允许的(⽽且在不少地⽅可以看到这样的代码),但Google编程风格对此不做要求。即使对于已经使⽤⽔平对齐的代码,我们也不需要去保持这种风格。
以下⽰例先展⽰未对齐的代码,然后是对齐的代码:
private int x; // this is fine
private Color color; // this too
private int  x;      // permitted, but future edits
private Color color;  // may leave it unaligned
Tip:对齐可增加代码可读性,但它为⽇后的维护带来问题。考虑未来某个时候,我们需要修改⼀堆对齐的代码中的⼀⾏。这可能导致原本很漂亮的对齐代码变得错位。很可能它会提⽰你调整周围代码的空⽩来使这⼀堆代码重新⽔平对齐(⽐如程序员想保持这种⽔平对齐的风格),这就会让你做许多的⽆⽤功,增加了reviewer的⼯作并且可能导致更多的合并冲突。
4.7 ⽤⼩括号来限定组:推荐
除⾮作者和reviewer都认为去掉⼩括号也不会使代码被误解,或是去掉⼩括号能让代码更易于阅读,否则我们不应该去掉⼩括号。我们没有理由假设读者能记住整个Java运算符优先级表。
4.8 具体结构
4.8.1 枚举类
枚举常量间⽤逗号隔开,换⾏可选。
没有⽅法和⽂档的枚举类可写成数组初始化的格式:
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
由于枚举类也是⼀个类,因此所有适⽤于其它类的格式规则也适⽤于枚举类。
4.8.2 变量声明
4.8.2.1 每次只声明⼀个变量
不要使⽤组合声明,⽐如int a, b;。
4.8.2.2 需要时才声明,并尽快进⾏初始化
不要在⼀个代码块的开头把局部变量⼀次性都声明了(这是c语⾔的做法),⽽是在第⼀次需要使⽤它时才声明。局部变量在声明时最好就进⾏初始化,或者声明后尽快进⾏初始化。
4.8.3 数组
4.8.3.1 数组初始化:可写成块状结构
数组初始化可以写成块状结构,⽐如,下⾯的写法都是OK的:
new int[] {
0, 1, 2, 3
}
new int[] {
0,
1,
2,
3
}
new int[] {
0, 1,
2, 3
}
new int[]
{0, 1, 2, 3}
4.8.3.2 ⾮C风格的数组声明
中括号是类型的⼀部分:String[] args,⽽⾮String args[]。
4.8.4 switch语句
术语说明:switch块的⼤括号内是⼀个或多个语句组。每个语句组包含⼀个或多个switch标签(case FOO:或default:),后⾯跟着⼀条或多条语句。
4.8.4.1 缩进
与其它块状结构⼀致,switch块中的内容缩进为2个空格。
每个switch标签后新起⼀⾏,再缩进2个空格,写下⼀条或多条语句。
4.8.4.2 Fall-through:注释
在⼀个switch块内,每个语句组要么通过break, continue, return或抛出异常来终⽌,要么通过⼀条注释来说明程序将继续执⾏到下⼀个语句组,任何能表达这个意思的注释都是OK的(典型的是⽤// fall through)。这个特殊的注释并不需要在最后⼀个语句组(⼀般是default)中出现。⽰例:
switch (input) {
case1:
case2:
prepareOneOrTwo();
// fall through
case3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
4.8.4.3 default的情况要写出来
每个switch语句都包含⼀个default语句组,即使它什么代码也不包含。
4.8.5 注解(Annotations)
注解紧跟在⽂档块后⾯,应⽤于类、⽅法和构造函数,⼀个注解独占⼀⾏。这些换⾏不属于⾃动换⾏(第4.5节,⾃动换⾏),因此缩进级别不变。例如:
@Override
@Nullable
public String getNameIfPresent() { ... }
例外:单个的注解可以和签名的第⼀⾏出现在同⼀⾏。例如:
@Override public int hashCode() { ... }
应⽤于字段的注解紧随⽂档块出现,应⽤于字段的多个注解允许与字段出现在同⼀⾏。例如:
@Partial@Mock DataLoader loader;
参数和局部变量注解没有特定规则。
4.8.6 注释
4.8.6.1 块注释风格
块注释与其周围的代码在同⼀缩进级别。它们可以是/* ... */风格,也可以是// ...风格。对于多⾏的/* ... */注释,后续⾏必须从*开始,并且与前⼀⾏的*对齐。以下⽰例注释都是OK的。
/*
* This is          // And so          /* Or you can
* okay.            // is this.          * even do this. */
*/
注释不要封闭在由星号或其它字符绘制的框架⾥。
Tip:在写多⾏注释时,如果你希望在必要时能重新换⾏(即注释像段落风格⼀样),那么使⽤/* ... */。
4.8.7 Modifiers
类和成员的modifiers如果存在,则按Java语⾔规范中推荐的顺序出现。
public protected private abstract static final transient volatile synchronized native strictfp
5.1 对所有标识符都通⽤的规则
标识符只能使⽤ASCII字母和数字,因此每个有效的标识符名称都能匹配正则表达式\w+。
在Google其它编程语⾔风格中使⽤的特殊前缀或后缀,如name_, mName, s_name和kName,在Java编程风格中都不再使⽤。
5.2 标识符类型的规则
5.2.1 包名
包名全部⼩写,连续的单词只是简单地连接起来,不使⽤下划线。