原文地址:https://google.github.io/styleguide/javaguide.html
GIthub上GoogleCode风格的配置文件(支持Eclipse IDE和IntelliJ IDE):https://github.com/codeset/google-java-styleguide
本文档作为Java编程语言中源代码的Google编码标准的完整定义。当且仅当它遵守本文中的规则时,Java源文件被描述为在Google Style中。
与其他编程风格指南一样,所涵盖的问题不仅包括格式化的美学问题,也包括其他类型的约定或编码标准。但是,本文档主要关注我们普遍遵循的快速规则 ,并避免提供不可明确强制执行的建议(无论是通过人工还是工具)。
在本文件中,除非另有说明:
@interface
)。 其他“术语说明”将偶尔出现在整个文档中。
本文档中的示例代码是非规范的 。 也就是说,虽然示例是在Google风格,但它们可能不会说明代表代码的唯一时尚的方式。 示例中所做的可选格式选择不应作为规则强制执行。
源文件名由其包含的顶级类(其中包含正好一个 )的区分大小写的名称,以及.java
扩展名组成。
源文件以UTF-8编码。
除了行终止符序列, ASCII水平空格字符 ( 0x20 )是在源文件中任何位置出现的唯一的空格字符。这意味着:
对于具有特殊转义序列 ( \b
,\t
,\n
,\f
,\r
,\"
,\'
和\\
)的任何字符,使用该序列而不是相应的八进制Unicode(例如\u000a
)转义。
对于剩余的非ASCII字符,使用实际的Unicode字符(例如∞
)或等效的Unicode转义(例如\u221e
)。 选择仅取决于哪些使得代码更容易阅读和理解 ,尽管Unicode转义字符串字面值和注释强烈阻止。
提示:在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 |
良好:对不可打印字符使用转义,如有必要,请注释。 |
提示:不要因为某些程序可能无法正确处理非ASCII字符而使您的代码变得不可读。如果这应该发生,那些程序被打破 ,它们必须是固定的 。
源文件由以下顺序组成 :
正好一个空白线分隔存在的每个部分。
如果许可证或版权信息属于文件,则它属于此处。
包语句不是线包装 。 列限制(第4.4节, 列限制:100 )不适用于包语句。
不使用静态或其他方式的通配符导入 。
导入语句不是线包装的 。 列限制(第4.4节, 列限制:100 )不适用于import语句。
导入顺序如下:
如果存在静态和非静态导入,则单个空白行分隔两个块。 import语句之间没有其他空行。
在每个块中,导入的名称以ASCII排序顺序显示。 ( 注意:这与以ASCII排序顺序的import 语句不同 ,因为'。'排在';'前面)。
静态导入不用于静态嵌套类。 它们以正常进口进口。
每个顶级类都驻留在自己的源文件中。
为类的成员和初始化器选择的顺序可以对可学习性有很大的影响。 然而,没有一个正确的方法来做到这一点; 不同的类可以以不同的方式对其内容进行排序。
重要的是每个类使用一些逻辑顺序 ,维护者可以解释如果问。例如,新方法不仅习惯性地添加到类的末尾,因为这将产生“按照添加日期的顺序”排序,这不是逻辑排序。
当一个类有多个构造函数或者多个同名的方法时,这些顺序出现,中间没有其他代码(甚至不是私有成员)。
术语注意: 块状构造指的是类,方法或构造函数的主体。注意,通过关于数组初始化器的第4.8.3.1节,任何数组初始化器都可以被视为块状构造。
大括号与if
,else
,for
,do
和while
语句一起使用,即使主体为空或仅包含单个语句。
大括号遵循Kernighan和Ritchie风格(“ 埃及括号 ”)用于非空块和块状结构:
else
或逗号,那么大括号后面没有换行符。例子:
return () -> {
while (condition()) {
method();
}
};
return new MyClass() {
@Override public void method() {
if (condition()) {
try {
something();
} catch (ProblemException e) {
recover();
}
} else if (otherCondition()) {
somethingElse();
} else {
lastThing();
}
}
};
枚举类的一些例外在第4.8.1节“枚举类”中给出。
空块或块状构造可以是K&R样式(如第4.1.2节所述)。或者,它可以在打开后立即关闭,在({}
)之间没有字符或换行符,除非它是多块语句的一部分 (直接包含多个块:if/else
或try/catch/finally
)。
例子:
// This is acceptable
void doNothing() {}
// This is equally acceptable
void doNothingElse() {
}
// This is not acceptable: No concise empty blocks in a multi-block statement
try {
doSomething();
} catch (Exception e) {}
每次打开新的块或块状构造时,缩进增加两个空格。 当块结束时,缩进返回到上一缩进级别。 缩进级别适用于整个块中的代码和注释。 (请参见第4.1.2节“ 非空块:K&R Style”中的示例。)
每个语句后面都有换行符。
Java代码的列限制为100个字符。 除非如下所述,否则超过此限制的任何行都必须被换行,如第4.5节“ 换行”中所述。
例外:
package
和import
语句(见第3.2节包语句和3.3导入语句 )。 术语注意:当可能合法占用单个行的代码被分为多行时,此活动称为行换行 。
没有全面的,确定性的公式,显示每种情况下如何包装。 通常有几种有效的方法来换行同一段代码。
注意:虽然换行的典型原因是为了避免溢出列限制,即使在事实上符合列限制的代码也可能由作者自行决定。
提示:提取方法或局部变量可以解决问题,而不需要换行。
线包装的主要指令是:更喜欢在更高的语法层面打破。 也:
.
) <TextendsFoo&Bar>
符号(<TextendsFoo&Bar>
) catch (FooException|BarException e)
)。for
(“foreach”)语句中的“赋值运算符”冒号。 (
))。 ,
)保持附加到它前面的令牌。 MyLambda lambda =
(String label, Long value, Object obj) -> {
...
};
Predicate predicate = str ->
longExpressionInvolving(str);
注意:换行的主要目标是具有清除代码, 不一定代码适合最小的行数。
当换行时,第一行(每个连续行 )后面的每一行从原始行缩进至少+4。
当存在多个连续线时,根据需要,压痕可以变化超过+4。 一般来说,当且仅当它们以句法并行元素开头时,两个连续行使用相同的缩进级别。
关于水平对齐的第4.6.3节阐述了使用可变数量的空间将某些令牌与先前的行对齐的不鼓励做法。
将显示一个空白行:
允许多个连续的空行,但不需要(或鼓励)。
除了语言或其他样式规则所要求的之外,除了文字,注释和Javadoc之外,单个ASCII空间也仅出现在以下位置。
if
,for
或catch
)从该行后面的开括号((
))中分离else
或catch
)与该行上的关闭大括号(}
)分隔开 {
)之前,有两个例外:
@SomeAnnotation({a, b})
(不使用空格) String[][] x={{"foo"}};
({{
下面第8项)之间不需要空格,<TextendsFoo&Bar>
:<TextendsFoo&Bar>
catch (FooException|BarException e)
for
(“foreach”)语句中 (String str)-> str.length()
Object::toString
.
),它写作object.toString()
,:;
或右括号()
) //
)的两侧。 这里,允许多个空格,但不是必需的。 List<String> list
newint[]{5,6}
和newint[]{5,6}
都是有效的术语注意: 水平对齐是在代码中添加可变数量的附加空间的做法,目的是使某些令牌直接显示在之前行上的某些其他令牌下方。
这种做法是允许的,但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
可选的分组括号只有在作者和审稿人同意没有合理的机会,没有他们的代码将被误解,他们也不会使代码更容易阅读。假设每个读取器都具有存储的整个Java运算符优先级表是不合理的。
在遵循枚举常量的每个逗号后,换行符是可选的。 还允许附加空行(通常只有一个)。 这是一个可能性:
private enum Answer {
YES {
@Override public String toString() {
return "yes";
}
},
NO,
MAYBE
}
privete enum Clothes{CLUBS,HEARTS,SPADES,DIAMONDS}
每个变量声明(字段或本地)只声明一个变量:声明如int a, b;
不使用。
局部变量不习惯地在它们的包含块或块状构造的开始处声明。 相反,局部变量被声明为接近它们首次使用的点(在原因内),以最小化它们的范围。 局部变量声明通常具有初始化器,或者在声明之后立即初始化。
任何数组初始化器可以可选地被格式化为好像它是“块状构造”。 例如,以下都是有效的( 不是详尽的列表):
new int[] { new int[] {
0, 1, 2, 3 0,
} 1,
2,
new int[] { 3,
0, 1, }
2, 3
} new int[]
{0, 1, 2, 3}
方括号形成类型的一部分,而不是变量: String[] args
,而不是String args[]
。
术语注意: 交换机块的大括号内是一个或多个语句组 。每个语句组由一个或多个开关标签 (无论是case FOO:
或default:
:)组成,后跟一个或多个语句。
与任何其他块一样,开关块的内容缩进+2。
在切换标签之后,有一个换行符,缩进级别增加+2,就像打开一个块一样。 以下开关标签返回到上一缩进级别,如同一个块已关闭。
在开关块内,每个语句组都会突然终止(使用break
,continue
,return
或thrown异常),或者标记有注释,指示执行将继续或可能继续到下一个语句组。任何传达堕落想法的评论都是足够的(通常// fall through
)。在开关组的最后一个语句组中不需要此特殊注释。例:
switch (input) {
case 1:
case 2:
prepareOneOrTwo();
// fall through
case 3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
case1:
之后不需要注释,只在语句组的末尾。
default
情况存在每个switch语句包括一个default
语句组,即使它不包含代码。
应用于类,方法或构造函数的注释立即出现在文档块之后,并且每个注释都列在其自己的行(即每行一个注释)上。这些换行符不构成换行(第4.5节,换行 ),因此缩进级别不会增加。 例:
@Override
@Nullable
public String getNameIfPresent() { ... }
@Override public int hashCode() { ... }
@Partial @Mock DataLoader loader;
本节讨论实现注释 。 Javadoc在第7节Javadoc中单独解决。
任何换行符之前可以有任意空格,然后是实现注释。 这样的注释使该行非空白。
块注释缩进到与周围代码相同的级别。 它们可以是/* ... */
style或// ...
样式。 对于多行/* ... */
注释,后续行必须以*
与上一行的*
对齐开始。
/*
* This is // And so /* Or you can
* okay. // is this. * even do this. */
*/
提示:在编写多行注释时,如果您希望自动代码格式化程序在必要时重新换行(段落样式),请使用/* ... */
样式。大多数格式化程序不会在// ...
样式注释块中重新换行。
类和成员修饰符(如果存在)按照Java语言规范建议的顺序显示:
public protected private abstract default static final transient volatile synchronized native strictfp
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中 。
类名通常是名词或名词短语。 例如, Character
或ImmutableList
。接口名称也可以是名词或名词短语(例如,List
),但有时可以是形容词或形容词短语(例如,Readable
)。
没有特定的规则,甚至没有成熟的惯例为命名注释类型。
测试类从它们正在测试的类的名称开始命名,并以Test
结束。例如,HashTest
或HashIntegrationTest
。
方法名称写在lowerCamelCase中 。
方法名称通常是动词或动词短语。 例如,sendMessage
或stop
。
下划线可能出现在JUnit 测试方法名称中以分隔名称的逻辑组件。 一个典型的模式是test
,例如testPop_emptyStack
。没有一个正确的方法来命名测试方法。
常量名称使用CONSTANT_CASE
:所有大写字母,用下划线分隔的单词。但什么是常数,究竟是什么?
常数是静态最终字段,其内容是不可变的,并且其方法没有可检测的副作用。 这包括基元,字符串,不可变类型和不可变类型的不可变集合。 如果任何实例的observable状态可以改变,它不是一个常量。只是打算从来不改变对象是不够的。例子:
// Constants
static final int NUMBER = 5;
static final ImmutableList NAMES = ImmutableList.of("Ed", "Ann");
static final ImmutableMap AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
static final Joiner COMMA_JOINER = Joiner.on(','); // because Joiner is immutable
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }
// Not constants
static String nonFinal = "non-final";
final String nonStatic = "non-static";
static final Set mutableCollection = new HashSet();
static final ImmutableSet mutableElements = ImmutableSet.of(mutable);
static final ImmutableMap mutableValues =
ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2);
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};
非常量字段名(静态或其他)写在lowerCamelCase中 。
这些名称通常是名词或名词短语。 例如,computedValues
或index
。
参数名称写在lowerCamelCase中 。
应该避免公共方法中的单字符参数名称。
局部变量名写在lowerCamelCase中 。
即使最终和不可变的局部变量不被认为是常量,并且不应该被定型为常量。
每个类型变量都以两种样式之一命名:
E
,T
,X
,T2
)T
(示例:RequestT
,FooBarT
)。有时,有一个以上的合理方式将英语短语转换为骆驼情况,例如当首字母缩略词或不寻常的结构,如“IPv6”或“iOS”存在。为了提高可预测性,Google Style指定以下(几乎)确定性方案。
从名称的散文形式开始:
注意,原始单词的壳体几乎完全被忽略。 例子:
散文形式 | 正确 | 不正确 |
---|---|---|
“XML HTTP请求” | XmlHttpRequest |
XMLHTTPRequest |
“新客户ID” | newCustomerId |
newCustomerID |
“内部秒表” | innerStopwatch |
innerStopWatch |
“在iOS上支持IPv6? | supportsIpv6OnIos |
supportsIPv6OnIOS |
“YouTube进口商” | YouTubeImporter YoutubeImporter * |
*可接受,但不推荐。
注意:某些单词在英语中有不明确的连字符:例如“nonempty”和“non-empty”都是正确的,所以方法名称checkNonempty
和checkNonEmpty
也是正确的。
@Override
:始终使用一个方法在合法时用@Override
注释标记。这包括重写超类方法的类方法,实现接口方法的类方法和重定义超接口方法的接口方法。
异常:当父方法为@Deprecated
时,可以省略@Deprecated
。
除非如下所述,在响应捕获的异常时不执行任何操作是非常不正确的。 (典型的响应是记录它,或者如果它被认为是“不可能”,将其重新抛出为一个AssertionError
。)
当在catch块中没有采取任何行动是真正合适的时候,这是合理的原因在注释中解释。
try {
int i = Integer.parseInt(response);
return handleNumericResponse(i);
} catch (NumberFormatException ok) {
// it's not numeric; that's fine, just continue
}
return handleTextResponse(response);
expected
开始,
则可以忽略捕获的异常而不进行注释。
以下是一个非常常见的用于确保测试中的代码确实抛出了预期类型的异常的习语,因此在此不需要注释。
try {
emptyStack.pop();
fail();
} catch (NoSuchElementException expected) {
}
当对静态类成员的引用必须限定时,它将使用该类的名称限定,而不是该类的类型的引用或表达式。
Foo aFoo = ...;
Foo.aStaticMethod(); // good
aFoo.aStaticMethod(); // bad
somethingThatYieldsAFoo().aStaticMethod(); // very bad
覆盖Object.finalize
是非常罕见的 。
提示:不要这样做。 如果你绝对必须,首先阅读并理解有效的Java项目7,“避免终结者”,非常仔细,然后不这样做。
Javadoc块的基本格式如下例所示:
/**
* Multiple lines of Javadoc text are written here,
* wrapped normally...
*/
public int method(String p1) { ... }
/** An especially short bit of Javadoc. */
一个空行(即,仅包含对齐的前导星号( *
)的行)出现在段落之间,并在“at-clause”组(如果存在)之前。每个段落,但第一个在紧接第一个单词之前有后面没有空格。
任何使用的标准“at- @deprecated
”都出现在@param
@deprecated
,@return
@deprecated
, @return
, @param
@deprecated
这些@deprecated
,并且这四种类型不会出现空描述。当at-clause不适合单个行时,连续行从@
的位置缩进四(或更多)个空格。
每个Javadoc块以简短摘要片段开头。 这个片段非常重要:它是出现在某些上下文中的文本的唯一部分,例如类和方法索引。
这是一个片段 - 一个名词短语或动词短语,而不是一个完整的句子。 它不以A {@code Foo} is a...
开头A {@code Foo} is a...
,或者This method returns...
,也不会形成一个完整的命令句,如Save the record.
。然而,片段被大写和标点,好像它是一个完整的句子。
提示:常见的错误是以/** @return the customer ID */
编写简单的Javadoc。这是不正确的,应该更改为/** Returns the customer ID. */
/** Returns the customer ID. */
。
至少 ,Javadoc存在于每个public
类以及这种类的每个public
或protected
成员,除了下面列出的一些例外。
还可能存在其他Javadoc内容,如第7.3.4节“ 非必需Javadoc”中所述。
Javadoc对于“简单的,明显的”方法(如getFoo
是可选的,在真正和真正没有什么别的值得说,但“返回foo”。
重要提示:引用此例外是不恰当的,因为省略了典型读者可能需要知道的相关信息。例如,对于名为getCanonicalName
的方法,不要省略其文档(只有/** Returns the canonical name. */
),如果典型的读者可能不知道术语“canonical name”手段!
Javadoc并不总是出现在覆盖超类型方法的方法上。
其他类和成员根据需要或期望具有Javadoc。
每当实现注释用于定义类或成员的总体目的或行为时,该注释将改为写为Javadoc(使用/**
)。
非必需的Javadoc不是严格要求遵守第7.1.2,7.1.3和7.2节的格式化规则,但当然是建议。