Google Java Style

1 介紹

這份文檔是Google Java編程風(fēng)格規(guī)范的完整定義。當(dāng)且僅當(dāng)一個(gè)Java源文件符合此文檔中的規(guī)則, 我們才認(rèn)為它符合Google的Java編程風(fēng)格。

與其它的編程風(fēng)格指南一樣,這里所討論的不僅僅是編碼格式美不美觀的問(wèn)題, 同時(shí)也討論一些約定及編碼標(biāo)準(zhǔn)。然而,這份文檔主要側(cè)重于我們所普遍遵循的規(guī)則, 對(duì)于那些不是明確強(qiáng)制要求的,我們盡量避免提供意見(jiàn)。

1.1 術(shù)語(yǔ)說(shuō)明

本文檔除非特殊說(shuō)明:

  1. class(類(lèi)): 統(tǒng)指普通的class類(lèi)型、enum枚舉類(lèi)型、interface類(lèi)型和annotation類(lèi)型。
  2. comment(注釋): 總是指implementation comments(實(shí)現(xiàn)注釋?zhuān)?code>/* */)。我們不使用“文檔注釋”這樣的說(shuō)法,而會(huì)直接說(shuō)Javadoc。

其他術(shù)語(yǔ)說(shuō)明,將在文檔中需要說(shuō)明的地方單獨(dú)說(shuō)明。

1.2 文檔說(shuō)明

本文檔中的代碼并不一定符合所有規(guī)范。即使這些代碼遵循Google Style, 但這不是唯一的代碼規(guī)范。例子中可選的格式風(fēng)格也不應(yīng)該作為強(qiáng)制執(zhí)行的規(guī)范。

2 源碼文件基礎(chǔ)

2.1 文件名

源碼文件名由它所包含的頂級(jí)class的類(lèi)名(大小寫(xiě)敏感), 加上.java后綴組成.

2.2 文件編碼:UTF-8

源碼文件使用UTF-8編碼。

2.3 特殊字符

2.3.1 空格字符

除了換行符外,ASCII水平空白字符(0x20)是源碼文件中唯一支持的空格字符。這意味著:

  1. 其他空白字符將被轉(zhuǎn)義。
  2. Tab字符不被用作縮進(jìn)控制。

2.3.2 特殊轉(zhuǎn)義字符串

任何需要轉(zhuǎn)義字符串表示的字符(例如\b, \t, \n, \f, \r, \', \\等),采用這種轉(zhuǎn)義字符串的方式表示,而不采用對(duì)應(yīng)字符的八進(jìn)制數(shù)(例如: \012)或Unicode碼(例如 \u000a)表示。

2.3.3 非ASCII字符

對(duì)于其余非ASCII字符,直接使用Unicode字符(例如 ),或者使用對(duì)應(yīng)的Unicode碼(例如 \u221e)轉(zhuǎn)義,都是允許的。唯一需要考慮的是,何種方式更能使代碼容易閱讀和理解。

注意:在使用unicode碼轉(zhuǎn)義,或者甚至是有時(shí)直接使用unicode字符的時(shí)候,添加一點(diǎn)說(shuō)明注釋將對(duì)別人讀懂代碼很有幫助。

例子:

Example Discussion
String unitAbbrev = "μs"; 贊,即使沒(méi)有注釋也非常清晰
String unitAbbrev = "\u03bcs"; // "μs" 允許,但沒(méi)有理由要這樣做
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s" 允許,但這樣做顯得笨拙還容易出錯(cuò)
String unitAbbrev = "\u03bcs"; 很糟,讀者根本看不出這是什么
return '\ufeff' + content; // byte order mark Good,對(duì)于非打印字符,使用轉(zhuǎn)義,并在必要時(shí)寫(xiě)上注釋

注意:永遠(yuǎn)不要由于害怕某些程序可能無(wú)法正確處理非ASCII字符而讓你的代碼可讀性變差。如果出現(xiàn)這樣的問(wèn)題,應(yīng)該由出現(xiàn)問(wèn)題的程序去解決。

3 源碼文件結(jié)構(gòu)

源碼文件按照先后順序,由以下幾部分組成:

  1. License或者copyright聲明信息。(如果需要聲明)
  2. 包聲明語(yǔ)句。
  3. import語(yǔ)句。
  4. class類(lèi)聲明(每個(gè)源碼文件只能有唯一一個(gè)頂級(jí)class)。

每個(gè)部分之間應(yīng)該只有一行空行作為間隔。

3.1 License 或者 copyright的聲明信息。

如果需要聲明license或copyright信息,應(yīng)該在文件開(kāi)始時(shí)聲明。

3.2 包聲明

包聲明的行,沒(méi)有行長(zhǎng)度的限制。單行長(zhǎng)度限制(4.4部分有詳細(xì)說(shuō)明,80或100)不適用于包聲明。

3.3 Import語(yǔ)句

3.3.1 不使用通配符import

不應(yīng)該使用通配符import,不管是否是靜態(tài)導(dǎo)入。

3.3.2 沒(méi)有行長(zhǎng)度限制

import語(yǔ)句的行,沒(méi)有行長(zhǎng)度的限制。單行長(zhǎng)度限制(4.4部分有詳細(xì)說(shuō)明,80或100)不適用于import語(yǔ)句所在行。

3.3.3 順序和空行

import語(yǔ)句應(yīng)該被分為幾個(gè)組,每個(gè)組之間由單行的空行隔開(kāi)。分組的順序如下:

  1. 所有的static import為歸為一組。
  2. com.google 包的import歸為一組。
  3. 使用的第三方包的引用。每個(gè)頂級(jí)第三方包歸為一組。第三方包之間按ASCII碼排序。例如:android, com, junit, org, sun
  4. java包歸為一組。
  5. javax包歸為一組。

同一組內(nèi)的import語(yǔ)句之間不應(yīng)用空行隔開(kāi)。同一組中的import語(yǔ)句按ASCII碼排序。

3.4 類(lèi)聲明

3.4.1 只聲明唯一一個(gè)頂級(jí)class

每個(gè)源碼文件中只能有一個(gè)頂級(jí)class。package-info.java文件除外。

3.4.2 類(lèi)成員順序

類(lèi)成員的順序?qū)Υa的易讀性有很大影響,但是沒(méi)有一個(gè)統(tǒng)一正確的標(biāo)準(zhǔn)。不同的類(lèi)可能有不同的排序方式。

重要的是,每個(gè)class都要按照一定的邏輯規(guī)律排序。當(dāng)被問(wèn)及時(shí),能夠解釋清楚為什么這樣排序。例如,新增加的成員方法,不是簡(jiǎn)單地放在class代碼最后面,按日期排序不是按邏輯排序。

3.4.2.1 重載方法:不應(yīng)該分開(kāi)

當(dāng)一個(gè)類(lèi)有多個(gè)構(gòu)造函數(shù),或者多個(gè)同名成員方法時(shí),這些函數(shù)應(yīng)該寫(xiě)在一起,不應(yīng)該被其他成員分開(kāi)。

4 格式

術(shù)語(yǔ)說(shuō)明:塊狀結(jié)構(gòu)(block-like construct)指類(lèi)、成員函數(shù)和構(gòu)造函數(shù)的實(shí)現(xiàn)部分(花括號(hào)中間部分)。注意,在后面的4.8.3.1節(jié)中講到數(shù)組初始化,所有的數(shù)組初始化都可以被認(rèn)為是一個(gè)塊狀結(jié)構(gòu)(非強(qiáng)制)。

4.1 花括號(hào)

4.1.1 花括號(hào)在需要的地方使用

花括號(hào)一般用在if, else, for, do, 和 while等語(yǔ)句。甚至當(dāng)它的實(shí)現(xiàn)為空或者只有一句話(huà)時(shí),也需要使用。

4.1.2 非空語(yǔ)句塊采用K&R風(fēng)格

對(duì)于非空語(yǔ)句塊,花括號(hào)遵循K&R風(fēng)格:

  • 左括號(hào)前不換行。
  • 左括號(hào)后換行。
  • 右括號(hào)前換行。
  • 如果右括號(hào)結(jié)束一個(gè)語(yǔ)句塊或者函數(shù)體、構(gòu)造函數(shù)體或者有命名的類(lèi)體,則需要換行。例如,當(dāng)右括號(hào)后面接else或者逗號(hào)時(shí),不應(yīng)該換行。

例子:

return new MyClass() {
  @Override public void method() {
    if (condition()) {
      try {
        something();
      } catch (ProblemException e) {
        recover();
      }
    }
  }
};

一些例外的情況,將在4.8.1節(jié)講枚舉類(lèi)型的時(shí)候講到。

4.1.3 空語(yǔ)句塊:使代碼更簡(jiǎn)潔

一個(gè)空的語(yǔ)句塊,可以在左花括號(hào)之后直接接右花括號(hào),中間不需要空格或換行。但是當(dāng)一個(gè)由幾個(gè)語(yǔ)句塊聯(lián)合組成的語(yǔ)句塊時(shí),則需要換行。(例如:if/else-if/else or try/catch/finally).

例子:

void  doNothing ()  {}

4.2 語(yǔ)句塊的縮進(jìn):2空格

每當(dāng)一個(gè)新的語(yǔ)句塊產(chǎn)生,縮進(jìn)就增加兩個(gè)空格。當(dāng)這個(gè)語(yǔ)句塊結(jié)束時(shí),縮進(jìn)恢復(fù)到上一層級(jí)的縮進(jìn)格數(shù)??s進(jìn)要求對(duì)整個(gè)語(yǔ)句塊中的代碼和注釋都適用。(例子可參考之前4.1.2節(jié)非空語(yǔ)句塊采用K&R風(fēng)格)。

4.3 一行一個(gè)語(yǔ)句

每個(gè)語(yǔ)句后要換行

4.4 行長(zhǎng)度限制:80或100

不同的項(xiàng)目可以選擇采用80個(gè)字符或者100個(gè)字符作為限制。除了以下幾個(gè)特殊情況外,其他代碼內(nèi)容都需要遵守這個(gè)長(zhǎng)度限制。這在4.5節(jié)長(zhǎng)行斷行會(huì)有詳細(xì)解釋。

例外:

  1. 按照行長(zhǎng)度限制,無(wú)法實(shí)現(xiàn)地方(例如:javadoc中超長(zhǎng)的URL地址, 或者一個(gè)超長(zhǎng)的JSNI方法的引用);
  2. packageimport語(yǔ)句不受長(zhǎng)度限制。(見(jiàn)3.2包聲明、3.3節(jié)Import語(yǔ)句);
  3. 注釋中的命令行指令行,將被直接復(fù)制到shell中執(zhí)行的。

4.5 長(zhǎng)行斷行

術(shù)語(yǔ)說(shuō)明: 當(dāng)一行代碼按照其他規(guī)范都合法,只是為了避免超出行長(zhǎng)度限制而換行時(shí),稱(chēng)為長(zhǎng)行斷行。

長(zhǎng)行斷行,沒(méi)有一個(gè)適合所有場(chǎng)景的全面、確定的規(guī)范。但很多相同的情況,我們經(jīng)常使用一些行之有效的斷行方法。

注意:將長(zhǎng)行封裝為函數(shù),或者使用局部變量的方法,也可以解決一些超出行長(zhǎng)度限制的情況。并非一定要斷行。

4.5.1 在何處斷行

斷行的主要原則是:選擇在更高一級(jí)的語(yǔ)法邏輯的地方斷行。其他一些原則如下:

  1. 如果在非賦值運(yùn)算符處斷開(kāi),那么在該符號(hào)前斷開(kāi)(比如+,它將位于下一行)。
    注意: 這一點(diǎn)與Google其它語(yǔ)言的編程風(fēng)格不同(如C++和JavaScript)。 這條規(guī)則也適用于以下“類(lèi)運(yùn)算符”符號(hào):點(diǎn)分隔符(.),類(lèi)型界限中的&(<T extends Foo & Bar>),catch塊中的管道符號(hào)(catch (FooException | BarException e)
  2. 如果在賦值運(yùn)算符處斷開(kāi),通常的做法是在該符號(hào)后斷開(kāi)(比如=,它與前面的內(nèi)容留在同一行)。這條規(guī)則也適用于foreach語(yǔ)句中的分號(hào)。
  3. 方法名或構(gòu)造函數(shù)名與左括號(hào)留在同一行。
  4. 逗號(hào)(,)與其前面的內(nèi)容留在同一行。

4.5.2 斷行的縮進(jìn):至少4個(gè)字符

當(dāng)斷行之后,在第一行之后的行,我們叫做延續(xù)行。每一個(gè)延續(xù)行在第一行的基礎(chǔ)上至少縮進(jìn)四個(gè)字符。
當(dāng)原行之后有多個(gè)延續(xù)行的情況,縮進(jìn)可以大于4個(gè)字符。如果多個(gè)延續(xù)行之間由同樣的語(yǔ)法元素?cái)嘈?,它們可以采用相同的縮進(jìn)。
第4.6.3節(jié)介紹水平對(duì)齊中,解決了使用多個(gè)空格與之前行縮進(jìn)對(duì)齊的問(wèn)題。

4.6 空白空間

4.6.1 垂直空白

單行空行在以下情況使用:

  1. 類(lèi)成員間需要空行隔開(kāi):例如:成員變量、構(gòu)造函數(shù)成員函數(shù)、內(nèi)部類(lèi)、靜態(tài)初始化語(yǔ)句塊(static initializers)、實(shí)例初始化語(yǔ)句塊(instance initializers)。
    例外:成員變量之間的空白行不是必需的。一般多個(gè)成員變量中間的空行,是為了對(duì)成員變量做邏輯上的分組。
  2. 在函數(shù)內(nèi)部,根據(jù)代碼邏輯分組的需要,設(shè)置空白行作為間隔。
  3. 類(lèi)的第一個(gè)成員之前,或者最后一個(gè)成員結(jié)束之后,用空行間隔。(可選)
  4. 本文檔中其他部分介紹的需要空行的情況。(例如 3.3節(jié)中的import語(yǔ)句

單空行時(shí)使用多行空行是允許的,但是不要求也不鼓勵(lì)。

4.6.2 水平空白

除了語(yǔ)法、其他規(guī)則、詞語(yǔ)分隔、注釋和javadoc外,水平的ASCII空格只在以下情況出現(xiàn):

  1. 所有保留的關(guān)鍵字與緊接它之后的位于同一行的左括號(hào)之間需要用空格隔開(kāi)。(例如if、for、catch
  2. 所有保留的關(guān)鍵字與在它之前的右花括號(hào)之間需要空格隔開(kāi)。(例如elsecatch
  3. 在左花括號(hào)之前都需要空格隔開(kāi)。只有兩種例外:@SomeAnnotation({a, b})、String [][] x = {{"foo"}};
  4. 所有的二元運(yùn)算符和三元運(yùn)算符的兩邊,都需要空格隔開(kāi)。
  5. 逗號(hào)、冒號(hào)、分號(hào)和右括號(hào)之后,需要空格隔開(kāi)。
  6. // 雙斜線(xiàn)開(kāi)始一行注釋時(shí)。雙斜線(xiàn)兩邊都應(yīng)該用空格隔開(kāi)。并且可使用多個(gè)空格,但是不做強(qiáng)制要求。
  7. 變量聲明時(shí),變量類(lèi)型和變量名之間需要用空格隔開(kāi)。
  8. 初始化一個(gè)數(shù)組時(shí),花括號(hào)之間可以用空格隔開(kāi),也可以不使用。(例如:new int[] {5, 6}new int[] { 5, 6 } 都可以)

注意:這一原則不影響一行開(kāi)始或者結(jié)束時(shí)的空格。只針對(duì)行內(nèi)部字符之間的隔開(kāi)。

4.6.3 水平對(duì)齊:不做強(qiáng)制要求

術(shù)語(yǔ)說(shuō)明: 水平對(duì)齊,是指通過(guò)添加多個(gè)空格,使本行的某一符號(hào)與上一行的某一符號(hào)上下對(duì)齊。
這種對(duì)齊是被允許的,但是不會(huì)做強(qiáng)制要求。
以下是沒(méi)有水平對(duì)齊和水平對(duì)齊的例子;

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

注意:水平對(duì)齊能夠增加代碼的可讀性,但是增加了未來(lái)維護(hù)代碼的難度??紤]到維護(hù)時(shí)只需要改變一行代碼,之前的對(duì)齊可以不需要改動(dòng)。為了對(duì)齊,你更有可能改了一行代碼,同時(shí)需要更改附近的好幾行代碼,而這幾行代碼的改動(dòng),可能又會(huì)引起一些為了保持對(duì)齊的代碼改動(dòng)。那原本這行改動(dòng),我們稱(chēng)之為“爆炸半徑”。這種改動(dòng),在最壞的情況下可能會(huì)導(dǎo)致大量的無(wú)意義的工作,即使在最好的情況下,也會(huì)影響版本歷史信息,減慢代碼review的速度,引起更多merge代碼沖突的情況。

4.7 分組括號(hào):建議使用

非必須的分組括號(hào)只有在編寫(xiě)代碼者和代碼審核者都認(rèn)為大家不會(huì)因?yàn)闆](méi)有它而導(dǎo)致代碼理解錯(cuò)誤的時(shí)候,或者它不會(huì)使代碼更易理解的時(shí)候才能省略。沒(méi)有理由認(rèn)為所有閱讀代碼的人都能記住所有java運(yùn)算符的優(yōu)先級(jí)。

4.8 特殊結(jié)構(gòu)

4.8.1 枚舉類(lèi)型

每個(gè)逗號(hào)后接一個(gè)枚舉變量,不要求換行。
枚舉類(lèi)型,如果沒(méi)有函數(shù)和javadoc,處理格式是可以按照數(shù)組初始化來(lái)處理。

例子:

private  enum  Suit  {  CLUBS ,  HEARTS ,  SPADES ,  DIAMONDS  }

枚舉類(lèi)型也是一種類(lèi)(Class),因此Class類(lèi)的其他格式要求,也適用于枚舉類(lèi)型。

4.8.2 變量聲明

4.8.2.1 每次聲明一個(gè)變量

不要采用一個(gè)聲明,聲明多個(gè)變量。例如 int a, b;

4.8.2.2 當(dāng)需要時(shí)才聲明,盡快完成初始化

局部變量不應(yīng)該習(xí)慣性地放在語(yǔ)句塊的開(kāi)始處聲明,而應(yīng)該盡量離它第一次使用的地方最近的地方聲明,以減小它們的使用范圍。
局部變量應(yīng)該在聲明的時(shí)候就進(jìn)行初始化。如果不能在聲明時(shí)初始化,也應(yīng)該盡快完成初始化。

4.8.3 數(shù)組

4.8.3.1 數(shù)組初始化:可以類(lèi)似塊代碼處理

所有數(shù)組的初始化,都可以采用和塊代碼相同的格式處理。例如以下格式都是允許的:

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風(fēng)格一樣聲明數(shù)組

方括號(hào)應(yīng)該是變量類(lèi)型的一部分,因此不應(yīng)該和變量名放在一起。例如:應(yīng)該是 String [] args,而不是 String args[]

4.8.4 switch語(yǔ)句

術(shù)語(yǔ)說(shuō)明: switch語(yǔ)句是指在switch花括號(hào)中,包含了一組或多組語(yǔ)句塊。每組語(yǔ)句塊都由一個(gè)或多個(gè)switch標(biāo)簽(例如:case FOO:或者 default:)打頭。

4.8.4.1 縮進(jìn)

和其他語(yǔ)句塊一樣,switch花括號(hào)之后縮進(jìn)兩個(gè)字符。
每個(gè)switch標(biāo)簽之后,后面緊接的非標(biāo)簽的新行,按照花括號(hào)相同的處理方式縮進(jìn)兩個(gè)字符。在標(biāo)簽結(jié)束后,恢復(fù)到之前的縮進(jìn),類(lèi)似花括號(hào)結(jié)束。

4.8.4.2 繼續(xù)向下執(zhí)行的注釋

在switch語(yǔ)句中,每個(gè)標(biāo)簽對(duì)應(yīng)的代碼執(zhí)行完后,都應(yīng)該通過(guò)語(yǔ)句結(jié)束(例如:break、continue、return 或拋出異常),否則應(yīng)該通過(guò)注釋說(shuō)明,代碼需要繼續(xù)向下執(zhí)行下一個(gè)標(biāo)簽的代碼。注釋說(shuō)明文字只要能說(shuō)明代碼需要繼續(xù)往下執(zhí)行都可以(通常是 //fall through)。這個(gè)注釋在最后一個(gè)標(biāo)簽之后不需要注釋。例如:

switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // fall through
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}
4.8.4.3 default標(biāo)簽需要顯式聲明

每個(gè)switch語(yǔ)句中,都需要顯式聲明default標(biāo)簽。即使沒(méi)有任何代碼也需要顯示聲明。

4.8.5 Annotations

Annotations應(yīng)用到類(lèi)、函數(shù)或者構(gòu)造函數(shù)時(shí),應(yīng)緊接javadoc之后。每一行只有一個(gè)Annotations。
Annotations所在行不受行長(zhǎng)度限制,也不需要增加縮進(jìn)。例如:

@Override
@Nullable
public  String  getNameIfPresent ()  {  ...  }

例外情況:
如果Annotations只有一個(gè),并且不帶參數(shù)。則它可以和類(lèi)或方法名放在同一行。例如:

@Override  public  int  hashCode ()  {  ...  }

Annotations應(yīng)用到成員變量時(shí),也是緊接javadoc之后。不同的是,多個(gè)annotations可以放在同一行。例如:

@Partial  @Mock   DataLoader  loader ;

對(duì)于參數(shù)或者局部變量使用Annotations的情況,沒(méi)有特定的規(guī)范。

4.8.6 注釋

4.8.6.1 語(yǔ)句塊的注釋風(fēng)格

注釋的縮進(jìn)與它所注釋的代碼縮進(jìn)相同??梢圆捎?/* */ 進(jìn)行注釋?zhuān)部梢杂?//進(jìn)行注釋。當(dāng)使用 /**/ 進(jìn)行多行注釋時(shí),每一行都應(yīng)該以 *開(kāi)始, 并且 `* 應(yīng)該上下對(duì)齊。

例如:

/*
 * This is          // And so           /* Or you can
 * okay.            // is this.          * even do this. */
 */

注意:多行注釋時(shí),如果你希望集成開(kāi)發(fā)環(huán)境能自動(dòng)對(duì)齊注釋?zhuān)銘?yīng)該使用 /**/,//一般不會(huì)自動(dòng)對(duì)齊。

4.8.7 修飾符

多個(gè)類(lèi)和成員變量的修飾符,按Java Lauguage Specification中介紹的先后順序排序。具體是:

public、protected、private、abstract、static、final、transient、volatile、synchronized、nativestrictfp

5 命名

5.1 適用于所有命名標(biāo)識(shí)符的通用規(guī)范

標(biāo)示符只應(yīng)該使用ASCII字母、數(shù)字和下劃線(xiàn),字母大小寫(xiě)敏感。因此所有的標(biāo)示符,都應(yīng)該能匹配正則表達(dá)式 \w+ 。
Google Style中,標(biāo)示符不需要使用特殊的前綴或后綴,例如: name_, mName , s_namekName

5.2 不同類(lèi)型的標(biāo)示符規(guī)范

5.2.1 包名

包名全部用小寫(xiě)字母,通過(guò) . 將各級(jí)連在一起。不應(yīng)該使用下劃線(xiàn)。

5.2.2 類(lèi)名

類(lèi)型的命名,采用以大寫(xiě)字母開(kāi)頭的大小寫(xiě)字符間隔的方式(UpperCamelCase)。
class命名一般使用名詞或名詞短語(yǔ)。interface的命名有時(shí)也可以使用形容詞或形容詞短語(yǔ)。annotation沒(méi)有明確固定的規(guī)范。

測(cè)試類(lèi)的命名,應(yīng)該以它所測(cè)試的類(lèi)的名字為開(kāi)頭,并在最后加上Test結(jié)尾。例如:HashTest 、 HashIntegrationTest。

5.2.3 方法名

方法命名,采用以小寫(xiě)字母開(kāi)頭的大小寫(xiě)字符間隔的方式(lowerCamelCase)。

方法命名一般使用動(dòng)詞或者動(dòng)詞短語(yǔ)。For example:sendMessage
or stop

在JUnit的測(cè)試方法中,可以使用下劃線(xiàn),用來(lái)區(qū)分測(cè)試邏輯的名字,經(jīng)常使用如下的結(jié)構(gòu):test <MethodUnderTest>_ <state> 。例如:testPop_emptyStack ,測(cè)試方法也可以用其他方式進(jìn)行命名。

5.2.4 常量名

常量命名,全部使用大寫(xiě)字符,詞與詞之間用下劃線(xiàn)隔開(kāi)。(CONSTANCE_CASE)。

常量是一個(gè)靜態(tài)成員變量,但不是所有的靜態(tài)成員變量都是常量。在選擇使用常量命名規(guī)則給變量命名時(shí),你需要明確這個(gè)變量是否是常量。例如,如果這個(gè)變量的狀態(tài)可以發(fā)生改變,那么這個(gè)變量幾乎可以肯定不是常量。只是計(jì)劃不會(huì)發(fā)生改變的變量不足以成為一個(gè)常量。

下面是常量和非常量的例子:

// Constants
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
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<String> mutableCollection = new HashSet<String>();
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};

常量一般使用名詞或者名詞短語(yǔ)命名。

5.2.5 非常量的成員變量名

非常量的成員變量命名(包括靜態(tài)變量和非靜態(tài)變量),采用lowerCamelCase命名。

一般使用名詞或名詞短語(yǔ)。

5.2.6 參數(shù)名

參數(shù)命名采用lowerCamelCase命名。

應(yīng)該避免使用一個(gè)字符作為參數(shù)的命名方式。

5.2.7 局部變量名

局部變量采用lowerCamelCase命名。它相對(duì)于其他類(lèi)型的命名,可以采用更簡(jiǎn)短寬松的方式。

但即使如此,也應(yīng)該盡量避免采用單個(gè)字母進(jìn)行命名的情況,除了在循環(huán)體內(nèi)使用的臨時(shí)變量。

即使局部變量是final、不可改變的,它也不能被認(rèn)為是常量,也不應(yīng)該采用常量的命名方式去命名。

5.2.8 類(lèi)型名

類(lèi)型名有兩種命名方式:

  1. 單獨(dú)一個(gè)大寫(xiě)字母,有時(shí)后面再跟一個(gè)數(shù)字。(例如,E、T、X、T2)。
  2. 像一般的class命名一樣(見(jiàn)5.2.2節(jié)),再在最后接一個(gè)大寫(xiě)字母。(例如,RequestT、FooBarT)。

5.3 駝峰式命(Camel case) 的定義

有時(shí)一些短語(yǔ)被寫(xiě)成Camel case的時(shí)候可以有多種寫(xiě)法。例如一些縮寫(xiě)詞匯,或者一些組合詞:IPv6 或者 iOS 等。
為了統(tǒng)一寫(xiě)法,Google style給出了一種幾乎可以確定為一種的寫(xiě)法。

  1. 將字符全部轉(zhuǎn)換為ASCII字符,并且去掉 ' 等符號(hào)。例如, "Müller's algorithm" 被轉(zhuǎn)換為 "Muellers algorithm" 。
  2. 將上一步轉(zhuǎn)換的結(jié)果拆分成一個(gè)一個(gè)的詞語(yǔ)。從空格處和從其他剩下的標(biāo)點(diǎn)符號(hào)處劃分。

    注意:一些已經(jīng)是Camel case的詞語(yǔ),也應(yīng)該在這個(gè)時(shí)候被拆分。(例如 AdWords 被拆分為 ad words)。但是例如iOS之類(lèi)的詞語(yǔ),它其實(shí)不是一個(gè)Camel case的詞語(yǔ),而是人們慣例使用的一個(gè)詞語(yǔ),因此不用做拆分。

  3. 經(jīng)過(guò)上面兩部后,先將所有的字母轉(zhuǎn)換為小寫(xiě),再把每個(gè)詞語(yǔ)的第一個(gè)字母轉(zhuǎn)換為大寫(xiě)。
  4. 最后,將所有詞語(yǔ)連在一起,形成一個(gè)標(biāo)示符。

注意:詞語(yǔ)原來(lái)的大小寫(xiě)規(guī)則,應(yīng)該被完全忽略。

以下是一些例子:

|Prose form|Correct| Incorrect|
|-----|-------|
|"XML HTTP request"| XmlHttpRequest| XMLHTTPRequest|
|"new customer ID"| newCustomerId| newCustomerID|
|"inner stopwatch"| innerStopwatch| innerStopWatch|
|"supports IPv6 on iOS?"| supportsIpv6OnIos| supportsIPv6OnIOS|
|"YouTube importer"| YouTubeImporter YoutubeImporter*| ||

** * **號(hào)表示可以接受,但是不建議使用。

注意,有些詞語(yǔ)在英文中,可以用 - 連接使用,也可以不使用 - 直接使用。例如 “nonempty”和 “non-empty”都是可以的。因此,方法名字為checkNonempty或者checkNonEmpty 都是可以的。

6 編程實(shí)踐

6.1 @override 都應(yīng)該使用

@override annotations只要是符合語(yǔ)法的,都應(yīng)該使用。

6.2 異常捕獲 不應(yīng)該被忽略

一般情況下,catch住的異常不應(yīng)該被忽略,而是都需要做適當(dāng)?shù)奶幚怼@鐚㈠e(cuò)誤日志打印出來(lái),或者如果認(rèn)為這種異常不會(huì)發(fā)生,則應(yīng)該作為斷言異常重新拋出。

如果這個(gè)catch住的異常確實(shí)不需要任何處理,也應(yīng)該通過(guò)注釋做出說(shuō)明。例如:

try {
  int i = Integer.parseInt(response);
  return handleNumericResponse(i);
} catch (NumberFormatException ok) {
  // it's not numeric; that's fine, just continue
}
return handleTextResponse(response);

例外:在測(cè)試類(lèi)里,有時(shí)會(huì)針對(duì)方法是否會(huì)拋出指定的異常,這樣的異常是可以被忽略的。但是這個(gè)異常通常需要命名為: expected。例如:

try {
  emptyStack.pop();
  fail();
} catch (NoSuchElementException expected) {
}

6.3 靜態(tài)成員的訪問(wèn):應(yīng)該通過(guò)類(lèi),而不是對(duì)象

當(dāng)一個(gè)靜態(tài)成員被訪問(wèn)時(shí),應(yīng)該通過(guò)class名去訪問(wèn),而不應(yīng)該使用這個(gè)class的具體實(shí)例對(duì)象。例如:

Foo aFoo = ...;
Foo.aStaticMethod(); // good
aFoo.aStaticMethod(); // bad
somethingThatYieldsAFoo().aStaticMethod(); // very bad

6.4 不使用Finalizers 方法

重載Object.finalize方法是非常非常罕見(jiàn)的。

注意:不應(yīng)該使用這以方法。如果你認(rèn)為你必須使用,請(qǐng)先仔細(xì)閱讀并理解 Effective Java 第七條 “ Avoid Finalizers”。然后不要使用它。

7 Javadoc

7.1 格式規(guī)范

7.1.1 通用格式

最基本的javadoc的通用格式如下例:

/**
* Multiple lines of Javadoc text are written here,
* wrapped normally...
*/
public int method(String p1) { ... }

或者為單行格式:

/** An especially short bit of Javadoc. */

通用格式在任何時(shí)候使用都是可以的。當(dāng)javadoc塊只有一行時(shí),可以使用單行格式來(lái)替代通用格式。

7.1.2 段落

空白行:是指javadoc中,上下兩個(gè)段落之間只有上下對(duì)齊的*字符的行。每個(gè)段落的第一行在第一個(gè)字符之前,有一個(gè)<p>標(biāo)簽,并且之后不要有任何空格。

7.1.3 @從句

所有標(biāo)準(zhǔn)的@從句,應(yīng)該按照如下的順序添加:@param@return、@throws、@deprecated。并且這四種@從句,不應(yīng)該出現(xiàn)在一個(gè)沒(méi)有描述的Javadoc塊中。
當(dāng)@從句無(wú)法在一行寫(xiě)完時(shí),應(yīng)該斷行。延續(xù)行在第一行的@字符的位置,縮進(jìn)至少4個(gè)字符單位。

7.2 摘要片段

每個(gè)類(lèi)或者成員的javadoc,都是由一個(gè)摘要片段開(kāi)始的。這個(gè)片段非常重要。因?yàn)樗穷?lèi)或者方法在使用時(shí)唯一能看到的文本說(shuō)明。

主要摘要只是一個(gè)片段,應(yīng)該是一個(gè)名詞短語(yǔ)或者動(dòng)詞短語(yǔ),而不應(yīng)該是一個(gè)完整的句子。但是它應(yīng)該像一個(gè)完整的句子一樣使用標(biāo)點(diǎn)符號(hào)。

注意:一種常見(jiàn)的錯(cuò)誤是以這種形式使用javadoc: */** @return the customer ID / ** .這是不對(duì)的。應(yīng)該改為: /**Returns the customer ID. */ ** .

7.3 何處應(yīng)該使用Javadoc

至少,Javadoc應(yīng)該應(yīng)用于所有的public類(lèi)、publicprotected的成員變量和方法。和少量例外的情況。

7.3.1 例外:方法本身已經(jīng)足夠說(shuō)明的情況

當(dāng)方法本身很顯而易見(jiàn)時(shí),可以不需要javadoc。例如:getFoo。沒(méi)有必要加上javadoc說(shuō)明“Returns the foo”。
單元測(cè)試中的方法基本都能通過(guò)方法名,顯而易見(jiàn)地知道方法的作用。因此不需要增加javadoc。

注意:如果有一些相關(guān)信息是需要讀者了解的,那么以上的例外不應(yīng)作為忽視這些信息的理由。例如,對(duì)于方法名getCanonicalName,就不應(yīng)該忽視文檔說(shuō)明,因?yàn)樽x者很可能不知道詞語(yǔ)canonical name 指的是什么 。當(dāng)大部分代碼閱讀者不知道canonical name是什么意思時(shí),不應(yīng)該省略Javadoc, 只能寫(xiě)** /** Returns the canonical name. */ **。

7.3.2 例外:重載方法

重載方法有時(shí)不需要再寫(xiě)Javadoc


Google Java Style原文
從Code Review 談如何做技術(shù)
Code Review中的幾個(gè)提示

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄前言源文件基礎(chǔ)源文件結(jié)構(gòu)格式命名約定編程實(shí)踐Javadoc后記 前言這份文檔是Google Java編程風(fēng)格規(guī)...
    燕京博士閱讀 495評(píng)論 1 1
  • Google Java Style 指南 1 前言 本文檔參考并翻譯自Google Java Style Guid...
    AlexMofer閱讀 11,295評(píng)論 0 4
  • 一個(gè)統(tǒng)一的編程風(fēng)格不但能夠增強(qiáng)代碼可讀性,也可以避免許多低級(jí)問(wèn)題。一個(gè)嚴(yán)格遵從編碼規(guī)范的團(tuán)隊(duì),代碼無(wú)論出自多少人之...
    七弦桐語(yǔ)閱讀 690評(píng)論 0 2
  • 不要活的太卑微,總是迎合別人,照著別人的想法活。
    無(wú)眠時(shí)閱讀 136評(píng)論 0 0
  • 我的影子拉得老長(zhǎng) 離你住的大樓近了 我走遠(yuǎn)了
    鹿寧先森閱讀 206評(píng)論 0 0

友情鏈接更多精彩內(nèi)容