原文地址:https://google.github.io/styleguide/javaguide.html
本文为Google java编程语言编码规范的完整定义。依照此规范编写的Java源码文件可以被称为Google Style。
和其他编程规范指南一样,规范不仅包括代码的结构美学,也包括了其他一些业界约定俗成的公约和普遍采用的标准。本文档中的规范基本都是业界已经达成共识的标准,我们尽量避免去定义那些还存在争议的地方。
在本文中(除非另有说明):
其它术语将在文档中单独说明。
本文档中的代码并不一定符合所有规范。即使这些代码遵循Google Style,但这不是唯一的代码规范。例子中可选的格式风格也不应该作为强制执行的规范。
源码文件名由它所包含的顶级class的类名(区分大小写),加上.java扩展名组成。
源码文件编码应为UTF-8。
除了换行符外,ASCII水平空白字符(0x20)是源码文件中唯一支持的空格字符。这意味着:
任何需要转义字符串表示的字符(例如\b, \t, \n, \f, \r, \’, \等),采用这种转义字符串的方式表示,而不采用对应字符的八进制数(例如 \012)或Unicode码(例如 \u000a)表示。
对于其余非ASCII字符,直接使用Unicode字符(例如 ∞),或者使用对应的Unicode码(例如 \u221e)转义,都是允许的。唯一需要考虑的是,何种方式更能使代码容易阅读和理解。
提示:在使用unicode码转义,或者甚至是有时直接使用unicode字符的时候,添加一点说明注释将对别人读懂代码很有帮助。
提示:不要因为担心一些程序无法正常处理ASCII字符而不使用它,从而导致代码易读性变差。如果出现这样的问题,应该由出现问题的程序去解决。
源码文件包括,依次是:
每个部分之间以一行空行分隔。
如果需要声明lincense或copyright信息,应该在文件开始时声明。
包声明没有长度限制,单行长度限制规范,不适用于包声明。
不应使用通配符import,不管是不是静态导入。
import语句的行,没有行长度的限制。单行长度限制规范,不适用于import语句所在行。
import的顺序如下:
如果同时存在静态导入与非静态导入,则以一个空白行分隔,import语句之间没有其它空行。
每一个组中,import的名称以ASCII排序显示。
静态导入不能用于静态嵌套类。它们可以正常导入。
每个源码文件中只能有一个顶级class。
类成员的顺序对代码的易读性有很大影响,但是没有一个统一正确的标准。不同的类可以以不同的方式对其内容进行排序。
重要的是,每个class都要按照一定的逻辑规律排序。当被问及时,能够解释清楚为什么这样排序。例如,新增加的成员方法,不是简单地放在class代码最后面,按日期排序不是按逻辑排序。
当一个类有多个构造函数或多个同名的方法时,这个函数要写在一些,中间不要有其它代码。
术语注:块状结构(block-like construct)指类、成员函灵敏和构造函数的主体。需要注意的是,在后面的4.8.3.1节中讲到的数组初始化,所有的数组初始化都可以被 认为是一个块状结构(非强制)。
大括号用在if,else,for,do,和while等语句。甚至当它的实现为空或者只有一句话时,也要使用。
对于非空语句块,大括号遵循Kernighan和Ritchie的风格:
一些例外的情况,将在4.8.1节讲枚举类型时讲到。
一个空的语句块,可以在大括号开始之后真接接结束大括号,中间不需要空格或换行。但是当一个由几个语句块联合组成的语句块时,则需要换行。(例如:if/else 或try/catch/finally)
每当一个新的语句块产生,缩进就增加两个空格。当这个语句块结束时,缩进恢复到上一层级的缩进格数。缩进要求对整个语句块中的代码和注释都适用。(例子可参考之前4.1.2节中的例子)。
每句代码的结束都需要换行。
Java代码的单行限制长度为100个字符。除以下情况,超出此上限的行必须进行换行,如4.5节所解释的。
例外:
术语说明:当一行代码按照其他规范都合法,只是为了避免超出行长度限制而换行时,称为长行换行。
长行断行,没有一个适合所有场景的全面、确定的规范。但很多相同的情况,我们经常使用一些行之有效的断行方法。
注:将长行封装为函数,或者使用局部变量的方法,也可以解决一些超出行长度限制的情况。并非一定要断行。
提示:提取方法或局部变量可以解决该问题,而不需要长行换行。
换行的主要原则是:选择在更高一级的语法逻辑的地方断行。其他一些原则如下:
当一个非赋值运算的语句断行时,在运算符号之前断行。(这与Google的C++规范和JavaScrip规范等其他规范不同)。
这也适用于以下类似运算符的符号:
注:换行的主要目的是要清晰的代码,每行不一定适合最小的限制字符。
当断行之后,在第一行之后的行,我们叫做延续行。每一个延续行在第一行的基础上至少缩进四个字符。
当原行之后有多个延续行的情况,缩进可以大于4个字符。如果多个延续行之间由同样的语法元素断行,它们可以采用相同的缩进。
单行空行在以下情况使用:
单空行时使用多行空行是允许的,但是不要求也不鼓励。
除了语法、其他规则、词语分隔、注释和javadoc外,水平的ASCII空格只在以下情况出现:
在左花括号之前都需要空格隔开。只有两种例外:
@SomeAnnotation({a, b})
String[][] x = {{"foo"}};
所有的二元运算符和三元运算符的两边,都需要空格隔开。
注意:这一原则不影响一行开始或者结束时的空格。只针对行内部字符之间的隔开。
术语说明:水平对齐,是指通过添加多个空格,使本行的某一符号与上一行的某一符号上下对齐。
这种对齐是被允许的,但是不会做强制要求。
提示:水平对齐能够增加代码的可读性,但是增加了未来维护代码的难度。考虑到维护时只需要改变一行代码,之前的对齐可以不需要改动。为了对齐,你更有可能改 了一行代码,同时需要更改附近的好几行代码,而这几行代码的改动,可能又会引起一些为了保持对齐的代码改动。那原本这行改动,我们称之为“爆炸半径”。这 种改动,在最坏的情况下可能会导致大量的无意义的工作,即使在最好的情况下,也会影响版本历史信息,减慢代码review的速度,引起更多merge代码 冲突的情况。
非必须的分组括号只有在编写代码者和代码审核者都认为大家不会因为没有它而导致代码理解错误的时候,或者它不会使代码更易理解的时候才能省略。没有理由认为所有阅读代码的人都能记住所有java运算符的优先级。
在遵循枚举常量的每个逗号后,换行符是可选的,还允许附加空行(通常只有一个)。如下例子:
枚举类型也是一种类(Class),因此Class类的其他格式要求,也适用于枚举类型。
不要采用一个声明,声明多个变量。例如 int a, b;
局部变量不应该习惯性地放在语句块的开始处声明,而应该尽量离它第一次使用的地方最近的地方声明,以减小它们的使用范围。
局部变量应该在声明的时候就进行初始化。如果不能在声明时初始化,也应该尽快完成初始化。
所有数组的初始化,都可以采用和块代码相同的格式处理。例如以下格式都是允许的:
方括号应该是变量类型的一部分,因此不应该和变量名放在一起。例如:应该是String[] args,而不是 String args[] 。
术语说明:switch语句是指在switch花括号中,包含了一组或多组语句块。每组语句块都由一个或多个switch标签(例如case FOO:或者 default:)打头。
和其他语句块一样,switch花括号之后缩进两个字符。
每个switch标签之后,后面紧接的非标签的新行,按照花括号相同的处理方式缩进两个字符。在标签结束后,恢复到之前的缩进,类似花括号结束。
在 switch语句中,每个标签对应的代码执行完后,都应该通过语句结束(例如:break、continue、return 或抛出异常),否则应该通过注释说明,代码需要继续向下执行下一个标签的代码。注释说明文字只要能说明代码需要继续往下执行都可以(通常是 //fall through)。这个注释在最后一个标签之后不需要注释。例如:
每个switch语句中,都需要显式声明default标签。即使没有任何代码也需要显示声明。
Annotations应用到类、函数或者构造函数时,应紧接javadoc之后。每一行只有一个Annotations。
Annotations所在行不受行长度限制,也不需要增加缩进。例如:
例外情况:
如果Annotations只有一个,并且不带参数。则它可以和类或方法名放在同一行。例如:
Annotations应用到成员变量时,也是紧接javadoc之后。不同的是,多个annotations可以放在同一行。例如:
对于参数或者局部变量使用Annotations的情况,没有特定的规范。
注释的缩进与它所注释的代码缩进相同。可以采用 /* / 进行注释,也可以用 // 进行注释。当使用 /*/ 进行多行注释时,每一行都应该以 * 开始, 并且 * 应该上下对齐。
例如:
多行注释时,如果你希望集成开发环境能自动对齐注释,你应该使用 /**/, //一般不会自动对齐。
多个类和成员变量的修饰符,按Java Lauguage Specification中介绍的先后顺序排序。具体是:
long 值整型常量使用大写L后缀,从来没有小写(避免与数字1混淆)。例如:3000000000L而非3000000000l。
标示符只应该使用ASCII字母、数字和下划线,字母大小写敏感。因此所有的标示符,都应该能匹配正则表达式 \w+ 。
Google Style中,标示符不需要使用特殊的前缀或后缀,例如:name_, mName, s_name 和 kName。
包名全部用小写字母,通过 . 将各级连在一起。不应该使用下划线。
例如:
com.example.deepspace,而不是com.example.deepSpace或com.example.deep_space 。
类型的命名,采用以大写字母开头的大小写字符间隔的方式(UpperCamelCase)。
class命名一般使用名词或名词短语。interface的命名有时也可以使用形容词或形容词短语。annotation没有明确固定的规范。
测试类的命名,应该以它所测试的类的名字为开头,并在最后加上Test结尾。例如:HashTest 、 HashIntegrationTest。
方法命名,采用以小写字母开头的大小写字符间隔的方式(lowerCamelCase)。
方法命名一般使用动词或者动词短语。
在JUnit的测试方法中,可以使用下划线,用来区分测试逻辑的名字,经常使用如下的结构:test_ 。例如:testPop_emptyStack 。
测试方法也可以用其他方式进行命名。
常量命名,全部使用大写字符,词与词之间用下划线隔开。(CONSTANCE_CASE)。
常 量是一个静态成员变量,但不是所有的静态成员变量都是常量。在选择使用常量命名规则给变量命名时,你需要明确这个变量是否是常量。例如,如果这个变量的状 态可以发生改变,那么这个变量几乎可以肯定不是常量。只是计划不会发生改变的变量不足以成为一个常量。下面是常量和非常量的例子:
常量一般使用名词或者名词短语命名。
非常量的成员变量命名(包括静态变量和非静态变量),采用lowerCamelCase命名。
一般使用名词或名词短语。
参数命名采用lowerCamelCase命名。
应该避免使用一个字符作为参数的命名方式。
局部变量采用lowerCamelCase命名。它相对于其他类型的命名,可以采用更简短宽松的方式。
但即使如此,也应该尽量避免采用单个字母进行命名的情况,除了在循环体内使用的临时变量。
即使局部变量是final、不可改变的,它也不能被认为是常量,也不应该采用常量的命名方式去命名。
类型名有两种命名方式:
有时一些短语被写成Camel case的时候可以有多种写法。例如一些缩写词汇,或者一些组合词:IPv6 或者 iOS 等。
为了统一写法,Google style给出了一种几乎可以确定为一种的写法。
注意:词语原来的大小写规则,应该被完全忽略。以下是一些例子:
* 号表示可以接受,但是不建议使用。
提示:有些词语在英文中,可以用 - 连接使用,也可以不使用 - 直接使用。例如 “nonempty”和 “non-empty”都是可以的。因此,方法名字为checkNonempty 或者checkNonEmpty 都是可以的。
@Override annotations只要是符合语法的,都应该使用。
例外:当父类方法是@Deparecated时可省略@Override
一般情况下,catch住的异常不应该被忽略,而是都需要做适当的处理。例如将错误日志打印出来,或者如果认为这种异常不会发生,则应该作为断言异常重新抛出。
如果这个catch住的异常确实不需要任何处理,也应该通过注释做出说明。例如:
例外:在测试类里,有时会针对方法是否会抛出指定的异常,这样的异常是可以被忽略的。但是这个异常通常需要命名为: expected。例如:
当一个静态成员被访问时,应该通过class名去访问,而不应该使用这个class的具体实例对象。例如:
重载Object的finalize方法是非常非常罕见的。
注:不应该使用这以方法。如果你认为你必须使用,请先仔细阅读并理解 Effective Java 第七条 “Avoid Finalizers”。然后不要使用它。
通用格式在任何时候使用都是可以的。当javadoc块只有一行时,可以使用单行格式来替代通用格式。
空白行:是指javadoc中,上下两个段落之间只有上下对齐的 * 字符的行。每个段落的第一行在第一个字符之前,有一个
标签,并且之后不要有任何空格。
所有标准的@从句,应该按照如下的顺序添加:@param、@return、@throws、@deprecated。并且这四种@从句,不应该出现在一个没有描述的Javadoc块中。
当@从句无法在一行写完时,应该断行。延续行在第一行的@字符的位置,缩进至少4个字符单位。
每个类或者成员的javadoc,都是由一个摘要片段开始的。这个片段非常重要。因为它是类或者方法在使用时唯一能看到的文本说明。
主要摘要只是一个片段,应该是一个名词短语或者动词短语,而不应该是一个完整的句子。但是它应该像一个完整的句子一样使用标点符号。
注意:一种常见的错误是以这种形式使用javadoc:/* @return the customer ID /.这是不对的。应该改为:/* Returns the customer ID. /.
至少,Javadoc应该应用于所有的public类、public和protected的成员变量和方法。和少量例外的情况。例外情况如下。
当方法本身很显而易见时,可以不需要javadoc。例如:getFoo。没有必要加上javadoc说明“Returns the foo”。
单元测试中的方法基本都能通过方法名,显而易见地知道方法的作用。因此不需要增加javadoc。
注 意:有时候不应该引用此例外,来省略一些用户需要知道的信息。例如:getCannicalName 。当大部分代码阅读者不知道canonical name是什么意思时,不应该省略Javadoc,认为只能写/* Returns the canonical name. / 。
重载方法有时不需要再写Javadoc。
一些在包外不可见的class和成员变量或方法,根据需要,也可以使用javadoc。
当一个注释用以说明这个类、变量或者方法的总体目标或行为时,该注释应使用Javadoc(使用/**)