Google Java 代码规范
Contents
Translation of Google Java Style Guide,by Lee.
转载请注明出处.This Translation is under CC BY-NC-SA 3.0 CN
License.
目录
- 目录
- 1. 介绍
- 2. 源文件
- 3. 源文件格式
- 4. 格式化
- 5. 命名规则
- 6. 编程实践
- 7. Javadoc
1. 介绍
本文档作为Java编程语言中源代码编码规范的完整定义.当且仅当一个Java源文件遵守这里的规定时,才被称作符合Google Style.
像其他编程规范一样,这个项目涵盖的不仅仅是格式和审美问题,也包括了其他的规则和编码标准.然而,本文档主要专注于我们都遵守的明确的规定,并且避免给出不明确的规则.(无论是人还是工具)
1.1 术语说明
在此文档中,除非特殊说明:
-
术语
class
用来表示普通的类,枚举类,接口或注释类型(@interface
). -
术语
member
(一个类的) 用来表示 一个嵌套类,字段,方法和构造器.这些全都是一个类的顶级内容,除了初始化和注释. -
术语
comment
总是指实施注释(implementation comments).我们不使用文档注释(documentation comments),取而代之的是,术语Javadoc
.
其他术语偶尔会出现在后续文档里.
1.2 指南说明
文档中的示例代码是非规范的.也就是说,虽然这些示例代码是符合Google Style的,但并不意味着这是唯一的一种代码风格.示例中可选的代码格式不应该成为强硬的规定.
2. 源文件
2.1 文件名
源文件以其顶层的类名唯一性来命名,是大小写敏感的.以 .java
为扩展名.
2.2 文件编码
源文件的编码格式是 UTF-8
.
2.3 特殊字符
2.3.1 空白字符
除了行结束符序列,源文件中的所有空白字符都应该ASCII水平空白字符(0x20).这意味着:
- 字符串和字符文字中的所有其他空白字符都将被转义.
- 制表符(Tab)不能用来缩进.
2.3.2 特殊转义序列
任何有特殊转义序列(\b
, \t
, \n
, \f
, \r
, \"
, \'
,\\
)的字符,使用此序列而不是八进制(例如: \012
)或Unicode(例如: \u000a
)进行转义.
2.3.3 非ASCII字符
对于剩下的非ASCII字符,可以使用实际的Unicode字符(例如: ∞
),也可以使用等价的Unicode转义字符(例如: \u221e
).这取决于那种方式更易理解,尽管Unicode转义字符串和注释是不鼓励使用的.
提示:在用转义表示Unicode甚至有时用一些实际的Unicode时,写上注释很有用.
例子 | 描述 |
---|---|
String unitAbbrev = "\u03bcs"; // "μs" |
允许,但是没有理由这样做. |
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s" |
允许,但是容易引起错误 |
String unitAbbrev = "\u03bcs"; |
糟,读者无法理解 |
String unitAbbrev = "μs"; |
赞!十分清楚,即使没有注释 |
return '\ufeff' + content; // byte order mark |
好,对于非打印字符,使用转义.并且写上注释. |
提示:不要因为某些程序可能无法正确处理非ASCII字符而使您的代码变得不太可读.如果这发生了,这些程序必须被修复.
3. 源文件格式
3.1 许可或版权信息-如果存在
如果有文件内有许可或版权信息,那他只属于这个文件.
3.2 包语句
包语句是不能换行的.列限制(第4.4节,列限制:100)不适用于包语句
3.3 引入语句
3.3.1 不使用通配符引入
不要使用通配符导入,不论静态或其他方式.
3.3.2 不要换行
引入语句是不能换行的.列限制(第4.4节,列限制:100)不适用于引入语句
3.3.3 顺序和间距
导入语句的顺序如下:
- 所有静态导入在一个区块内.
- 所有非静态导入在一个区块内.
3.3.4 没有静态导入类
静态导入不用于静态嵌套类。他们需要正常导入。
3.4 类申明
3.4.1 唯一的一个顶层类
每个顶级类都位于自己的源文件中。
3.4.2 类成员顺序
类的成员和初始化的顺序对易学性有很大的影响。然而,没有一个正确的方法来做到这一点;不同的类可能会以不同的方式排序其成员。
重要的是每个类都使用一些逻辑顺序,如果被问到,维护者可以解释清楚.比如说,新的方法不应该仅仅被添加到类的末尾,因为这是按时间排序而不是按逻辑排序.
3.4.2.1 重载:不间断
当一个类有很多构造器或同名方法时,他们应该是连续的,不应该被间隔开(即使是私有方法).
4. 格式化
4.1 大括号
4.1.1 使用大括号即使可选
在 if
, else
, for
, do
, while
语句中应该使用大括号,即使是空语句或者只有一个语句.
4.1.2 非空块:K&R样式
在非空块和块状结构中,大括号遵守 Kernighan 和 Ritchie 风格(Egyptian brackets):
-
左括号前不换行.
-
左括号后换行.
-
右括号前换行.
-
当右括号是一个语句,函数体,构造方法,嵌套类的结尾时,右括号后换行.如果右括号后是
else
或者逗号,则不换行.
例子:
|
|
枚举类的几个例外在 第4.8.1节,枚举类.
4.1.3 空块:简洁
一个空块状结构或类块状结构可以用K & R 风格(在第4.1.2
节中).或者,大括号可以在打开后马上关闭,在{}
之间没有字符或换行符,除非它是多块语句(直接包含多个块:if/else
或try/catch/finally
)的一部分.
例子:
|
|
|
|
4.2 块缩进:+2空格
每当一个空块状结构或类块状结构被打开时,缩进就增加2个空格.当块结构结束时,缩进有回到和之前一样.(当然这些IDE都帮你做了.译者注)缩进级别适用于整个块中的代码和注释(参见第4.1.2节中的示例,非空块:K&R样式)
4.3 一行一句
每个语句独占一行.
4.4 列限制:100
Java代码的列限制为100个字符.除了如下所述,任何超过此限制的行都必须换行,如第4.5节,换行中所述.
例外:
- 不能遵守列限制的行(比如:Javadoc中一个超长URL或JSNI方法的引用).
package
和import
语句(见第3.2节 包语句 和第3.3节 引入语句 ).- 注释中可以复制到终端执行的命令行.
4.5 换行(Line-wrapping)
术语注解:当可以占用单行的代码被划分成多行时,这被称为换行.
没有一个全面的,确定性的公式,表明在每种情况下如何换行。通常有几种有效的方式来对同一行代码换行.
注意:尽管换行的主要原因是避免超过列限制,但是实际符合列限制的代码也可以由作者自行决定换行。
提示:提取方法或局部变量可以不换行就解决问题.
4.5.1 从哪里断开
自动换行的首要准则是:更倾向于在更高的语法级别处断开.
-
如果在一个非赋值运算符处断开,应该在该符号之前断开.(比如
+
,他应该在下一行.)这和其他语言的Google Style不同,比如 C++ 和 JavaScript.- 这也适用于以下“类运算符”符号
- 点分隔符 (
.
) - 双冒号方法引用 (
::
) - 类型界限中的和号(
&
) (<T extends Foo & Bar>
) - catch块中的管道符号(
FooException | BarException e)
)
- 点分隔符 (
- 这也适用于以下“类运算符”符号
-
如果在一个赋值运算符处断开,应该在该符号之后断开.(比如
=
,它与前面的内容留在同一行.译者注)但是两种方案都是可以的.- 这也适用于"类赋值运算符",比如
foreach
中的:
.
- 这也适用于"类赋值运算符",比如
-
方法名或构造方法名与左括号留在同一行。
-
逗号
,
于前面的内容在同一行. -
Lambda表达式的箭头处一般不会换行,除非lambda表达式只包含一个单独的无大括号的语句.例子:
|
|
注意:换行的主要目的是使代码清晰,不一定是最小行数的代码.
4.5.2 换行的语句至少+4空格
换行时,每个延续的行都要至少+4空格的缩进.
当有多个连续的行时,缩进可能不止4个空格.通常,当且仅当它们是语法上的并行元素时,才采用相同的缩进级别.
第4.6.3水平对齐一节中指出,不鼓励使用可变数目的空格来对齐前面行的符号。
4.6 空白
4.6.1 垂直空白
一个空白行出现在:
-
在类的连续成员或初始化之间:字段,构造方法,嵌套类,静态初始化块,实例初始化块.
- 例外:两个连续的字段(它们之间没有其他代码)之间的空白行是可选的.这种情况下,空白行用来对字段进行逻辑分组的.
- 例外:枚举常数之间的空白行(第4.8.1节 )
-
语句之间,根据需要把语句按逻辑分成组.
-
可选地,在第一个成员或初始化器之前,或者在该类的最后一个成员或初始化器之后(既不鼓励也不反对).
允许多个连续的空白行,但不鼓励.
4.6.2 水平空白
除了语言和其他风格规则的要求和文字,注释,Javadoc之外,单个的ASCII空格只出现在下面这几个地方.
-
分离保留字(比如
if
,for
,catch
)和紧随其后的左括号((
). -
分隔保留字与其前面的右大括号(
}
)(如else, catch)。 -
在任意的左括号(
{
)前,除了两个例外:@SomeAnnotation({a, b})
没有使用空格String[][] x = {{"foo"}};
没有使用空格
-
在任意二元或三元操作符两侧.这也适用于"类操作符":
-
类型界限中的
&
:<T extends Foo & Bar>
-
catch块中的管道符号: (
FooException | BarException e)
) -
foreach语句中的冒号(
:
). -
Lambda表达式的箭头:
(String str) -> str.length()
-
但是不适用于:
-
双冒号(
::
)的方法应用:Object::toString
-
句点操作符(
.
):object.toString()
-
-
在
,
:
;
及右括号)
之后. -
在注释的两个斜杠(
//
)两侧,这里允许多个空格,但不是必须的. -
在声明的类型和变量名之间:
List<String> list
-
可选的,在数组初始化的大括号两侧
new int[] {5, 6}
和new int[] { 5, 6 }
都可以.
4.6.3 水平对齐:不作要求
术语解释:*水平对齐(Horizontal alignment )*是在代码中添加可变数量空格的做法,目的是使某些内容与先前行的内容对齐.
这个做法是被允许,但是不作要求.甚至不需要在已经使用的地方保持水平对齐.
例子:
|
|
提示:对齐可增加代码的可读性,但也造成以后维护的麻烦.考虑以后,我们需要修改一堆对齐代码中的一行.这种变化可能会使代码不再对齐,但这是允许的.很多时候,这会促使你去调整附近行的空格,可能会触发一连串的修改.这一行代码的改变造成了连环反应.这最坏时将会导致无用功,但是它至少也造成了历史版本的破坏,减慢了审查人员的速度,并增加了合并冲突的可能。
4.7 括号分组:推荐
除非作者和审查员都认为去掉小括号也不会使代码被误解,或是去掉小括号能让代码更易于阅读,否则我们不应该去掉小括号.我们没有理由认为每位读者都知道Java运算符的优先级.
4.8 具体构造
4.8.1 枚举类
在每个逗号后,紧跟这一个枚举常量,也可以选择换行.额外的空行(通常只有一个)也是允许的。这是一种可能:
|
|
一个没有方法和文档的枚举类,可以选择像声明数组一样的格式(详见:第4.8.3.1节 数组初始化 ):
|
|
枚举类也是类,因此适用于类的所有其他规则都适用.
4.8.2 变量声明
4.8.2.1 每次只声明一个变量
每次只声明一个变量,像 int a, b;
这样是不允许的.
4.8.2.2 按需声明
不要习惯性地把局部变量一次性在代码块的开头声明,而是在第一次用到它的时候再声明,最小化它们的作用范围.局部变量声明通常要初始化,或在声明后立即初始化.
4.8.3 数组
4.8.3.1 数组可以"块状"初始化
任何数组都可以块状结构一样初始化.比如下面的例子都是合法的(不是详尽的列表):
|
|
4.8.3.2 非C风格的数组声明
方括号是类型的一部分,而不是变量名.采用 String[] args
而不是 String args[]
.
4.8.4 Switch语句
术语解释:switch
大括号内是一个或多个语句组.每个语句组包含一个或多个的switch
标签(case
和 default
),跟这一个或多个语句(如果是最后一个语句组,则是零个或多个).
4.8.4.1 缩进
与任何其他代码块一样,switch块内的缩进+2.
在switch标签后需要换行,并且再+2的缩进.下一个标签返回之前的缩进级别.
4.8.4.2 注释Fall-through
在switch块中,每个语句组那么通过 break
, continue
,return
或者抛出异常来结束语句,要么写明注释来表明它会进入下一个语句组.任何表达这个意思的注释都可以.(一般用 // fall through
)这个特殊的注释在最后一个语句组时不需要.比如:
|
|
4.8.4.3 default
要写出
每个switch语句都要包含 default
语句组,即使它是空的.
例外:一个对枚举常量的Switch语句,如果写出了所有的情况,则可以省略 default
语句组.
4.8.5 注解(Annotations)
用于类,方法和构造方法的注解,应该立即出现在文档后面,并且每个注解占一行,这不属于换行( line-wrapping )所以缩进不增加.
|
|
例外:单个无参的注解可以和语句同行,比如:
|
|
对于字段的注解也要立即出现在文档之后,但是这种情况下,多个注释可以在同一行.比如:
|
|
参数,局部变量和类型的注解没有特定规则。
4.8.6 注释(Comment)
这节讲implementation comments
,Javadoc在第7节Javadoc标记单独讲.
4.8.6.1 块状注释风格
注释块的缩进和周围的代码保持一致.可以写成 /*...*/
或 //...
.多行注释中,子行必须以*
开头和前一行对齐.
|
|
注释不包含在带有星号或其他字符的框框中.
提示: 如果你希望自动代码格式化程序在必要时换行,则编写多行注释时,请使用
/*...*/
. 大多数格式化程序不会在//
样式的注释块中重新换行
4.8.7 修饰符
类和成员的修饰符,以下面推荐的顺序出现:
|
|
4.8.8 数字
long类型的整型数字,使用大写L后缀(不要以小写l后缀,为了不和数字1混淆).比如:使用 3000000000L
而不是 3000000000l
.
5. 命名规则
5.1 对所有标识符的基本规则
标识符只包含ASCII中的字母和数字,并且在下面列举的少数情况下,使用下划线.所以每个合法的标识符多可以被 \w+
正则匹配.
在Google Style中,前缀和后缀是从不使用的,像这些:name_
, mName
, s_name
, kName
.
5.2 各种标识符的命名
5.2.1 包名的命名
包名全部是小写的,可以是几个单词连接起来(不包括下划线).比如:使用com.example.deepspace
而不是com.example.deepSpace
或com.example.deep_space
.
5.2.2 类名的命名
类名都以驼峰命名法命名.
类名通常是名词或名词短语.比如Character
或者ImmutableList
接口名也是名词或名词短语.(比如:List
),但是有时候可以是形容词或形容词短语(比如:Readable
).
注解类型没有特定的命名规则,甚至没有完善的约定.
Test类以他们需要测试的类命名,并加上Test.例子:HashTest
或HashIntegrationTest
.
5.2.3 方法的命名
方法名也都以驼峰命名法命名.
方法名一般可以是动词或动词短语.比如:sendMessage
或 stop
.
下划线可能出现在JUnit的测试方法中用以分隔名称的逻辑组件.一个典型的格式是:test<MethodUnderTest>_<state>
,比如,testPop_emptyStack
.没有准确的方法去命名测试类.
5.2.4 常量的命名
常量的命名可以使用 CONSTANT_CASE
规则:全部大写,包含下划线.但是讲真的,什么是常量?
常量是以 static final
修饰的,并且其内容永远不变,其方法没有可察觉的副作用.这包括 primitives
, String
, 不变的类型和不可变类型的不可变集合.如果任意的可观察的实例发生变化,那么它就不是常量.仅仅表现为改变的对象是远远不够的,比如:
|
|
这些常量名一般都是名词或名词短语.
5.2.5 非常量字段的命名
非常量字段(不论是static的或其他的)是以驼峰命名法命名的.
这些名称一般都是名词或名词短语.比如 computedValues
或 index
.
5.2.6 参数的命名
参数名也都以驼峰命名法命名.
应避免在公共方法中使用一个字符的参数名称.
5.2.7 局部变量的命名
局部变量名以驼峰命名法命名.
即使用 final
和 static
修饰,局部变量也不会被看做是常量,也不应该以常量的方式来命名.
5.2.8 类型变量的命名
类型变量可用以下两种风格之一进行命名:
- 单个的大写字母,后面可以跟一个数字(如:E,T,X,T2).
- 以类命名方式(详见5.2.2节 ),后面加个大写的T(如:RequestT,FooBarT).
5.3 驼峰命名法
有时会有几种不同"驼峰化"的方案,例如缩写或不寻常的单词像IPv6
和 iOS
.为了更准确的结果,Google Style作了以下(接近)精确的方案:
步骤:
-
把短语转换成只含ASCII码,并去掉
'
.比如,"Müller's algorithm"
,应该变成"Mullers algorithm"
-
把得到的结果以其中的空格和任意标点符号(一般是连字符)进行分割.
- 建议:如果任何一个词已经有了骆驼状外观,则把他分割成几个部分(比如,
"AdWords"
变成ad words
).请注意,诸如“iOS”这样的词不是真的骆驼式;它违反任何惯例,所以这个建议不适用.
- 建议:如果任何一个词已经有了骆驼状外观,则把他分割成几个部分(比如,
-
现在把每个词都小写(包括缩写),然后,大写第一个字.
-
最后,把每个单词组合起来.
例子:
名称 | 正确 | 错误 |
---|---|---|
“XML HTTP request” | XmlHttpRequest |
XMLHTTPRequest |
“YouTube importer” | YouTubeImporter YoutubeImporter * |
|
“inner stopwatch” | innerStopwatch |
innerStopWatch |
“new customer ID” | newCustomerId |
newCustomerID |
“supports IPv6 on iOS?” | supportIpv6OnIos |
supportsIPv6OnIOS |
*允许的,但不推荐.
注意:英语中有些词既可以带连字符又可以不带.比如,
nonempty
和non-empty
是一样的.所以checkNonempty
和checkNonEmpty
的命名方式都是对的.
6. 编程实践
6.1 @Override
:总是使用
只要是合法的,都要使用Override
.这包括了一个类方法重载父类方法,一个类方法实现接口的方法,一个接口方法重写父接口的方法.
例外: @Override
可以在它的父方法被@Deprecated
标记时省略.
6.2 捕捉的异常:不要忽视
除了下面的例外以外,对一个被捕捉的异常什么也不做是不对的.(一般的做法是去打印异常,),如果被认为是impossible
,则重新抛出AssertionError
异常.
下面的例子是真正可以在catch块中不采取任何行动的,理由应该在注释中解释.
|
|
例外:在测试中,如果其名称是或以expected
开头,则可以忽略捕获的异常,而无需注释。以下是一个非常常见的例子,用于确保正在测试的代码会抛出预期类型的异常,因此在此处不需要注释.
|
|
6.3 静态成员:使用类进行调用
使用类名调用静态方法,而不是具体对象或表达式.
|
|
6.4 Finalizers:禁用
真的非常少有人回去重载Object.finalize
.
提示:不要这样做.如果你铁了心要去做,请先仔细阅读并理解Effective Java Item 7中的"Avoid Finalizers".然后你会放弃这个想法的.XD
7. Javadoc
7.1 格式
7.1.1 一般格式
通常的Javadoc格式就像例子中的那样:
|
|
或者单行的Javadoc:
|
|
基本格式总是可行的.在Javadoc的内容(包括评论标记)可以包含在一行之内时,可以使用单行的Javadoc.注意这只能在没有块标记(例如,@return
)时使用.
7.1.2 段落
一个空行(也就是除了行最左边的*
外没有内容的),应该的段落之间,块标记(如果有的话)之前出现.每个段落,第一个但此前要有 <p>
,并且之后没有空格.
7.1.3 块标记
任何标准的"块标记"都有以@param
,@return
,@throws
,@deprecated
的顺序出现,并且这四个标签(如果出现)都要有内容.当描述无法在一行中容纳,连续行需要至少再缩进4个空格(从@
开始).
7.2 摘要片段
每个Javadoc块都应以一个简短的摘要片段开始.这个片段十分重要,在某些情况下,比如类或方法索引中,它是唯一出现的文本.
片段是名词或动词短语,而不是一个完整的句子.它不是以A {@code Foo} is a...
或This method returns...
开头的,也不是一个像Save the record.
这样完整的祈使句.然而,由于开头大写及被加了标点,它看起来像是个完整的句子.
提示:一个普遍的错误例子
/** @return the customer ID */
.它应该这样写/** Returns the customer ID. */
.
7.3 在哪里使用Javadoc
至少,每个public
的类及它的每个public
或protected
的成员都有写Javadoc.以下是几个例外.
额外的Javadoc也是可以的,详见第7.3.4节可选的Javadoc.
7.3.1 例外:不言自明的方法
Javadoc对于简单明白的方法可以省略,比如,getFoo
,因为这真的真的没有什么值得说的,就是"返回foo".
重要提示:如果有一些相关信息是需要读者了解的,那么以上的例外不应作为忽视这些信息的理由.例如,对于方法名getCanonicalName,就不要省略它的文档,基本上只要写上
/** Returns the canonical name. */
.因为一个普通的读者可能不知道"canonical name"是什么.
7.3.2 例外:重载
Javadoc在重载父方法时可以省略.
7.3.4 可选的Javadoc
其他类和成员根据需要或你的意愿写上Javadoc.
每当一个implementation comment
用来描述类或类成员的目的或行为时,该注释要用Javadoc(用/**
取代).
可选的Javadoc对以下的格式要求不严格(第7.1.2节,第7.1.3节和第7.2节),当然建议你遵守.