這份文檔是Google Java編程風格規範的完整定義。當且僅當一個Java源文件符合此文檔中的規則, 咱們才認爲它符合Google的Java編程風格。html
與其它的編程風格指南同樣,這裏所討論的不只僅是編碼格式美不美觀的問題, 同時也討論一些約定及編碼標準。然而,這份文檔主要側重於咱們所廣泛遵循的規則, 對於那些不是明確強制要求的,咱們儘可能避免提供意見。java
在本文檔中,除非另有說明:android
@interface
)其餘的術語說明會偶爾在後面的文檔出現。程序員
本文檔中的示例代碼並不做爲規範。也就是說,雖然示例代碼是遵循Google編程風格,但並不意味着這是展示這些代碼的惟一方式。 示例中的格式選擇不該該被強制定爲規則。正則表達式
源文件以其最頂層的類名來命名,大小寫敏感,文件擴展名爲.java
。shell
源文件編碼格式爲UTF-8。編程
除了行結束符序列,ASCII水平空格字符(0x20,即空格)是源文件中惟一容許出現的空白字符,這意味着:數組
對於具備特殊轉義序列的任何字符(\b, \t, \n, \f, \r, ", '及\),咱們使用它的轉義序列,而不是相應的八進制(好比\012
)或Unicode(好比\u000a
)轉義。app
對於剩餘的非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字符,若是真的有須要的話)
一個源文件包含(按順序地):
以上每一個部分之間用一個空行隔開。
若是一個文件包含許可證或版權信息,那麼它應當被放在文件最前面。
package語句不換行,列限制(4.4節)並不適用於package語句。(即package語句寫在一行裏)
即,不要出現相似這樣的import語句:import java.util.*;
import語句不換行,列限制(4.4節)並不適用於import語句。(每一個import語句獨立成行)
import語句可分爲如下幾組,按照這個順序,每組由一個空行分隔:
com.google
imports(僅當這個源文件是在com.google
包下)java
importsjavax
imports組內不空行,按字典序排列。
每一個頂級類都在一個與它同名的源文件中(固然,還包含.java
後綴)。
例外:package-info.java
,該文件中可沒有package-info
類。
類的成員順序對易學性有很大的影響,但這也不存在惟一的通用法則。不一樣的類對成員的排序多是不一樣的。 最重要的一點,每一個類應該以某種邏輯去排序它的成員,維護者應該要能解釋這種排序邏輯。好比, 新的方法不能老是習慣性地添加到類的結尾,由於這樣就是按時間順序而非某種邏輯來排序的。
3.4.2.1 重載:永不分離
當一個類有多個構造函數,或是多個同名方法,這些函數/方法應該按順序出如今一塊兒,中間不要放進其它函數/方法。
術語說明:塊狀結構(block-like construct)指的是一個類,方法或構造函數的主體。須要注意的是,數組初始化中的初始值可被選擇性地視爲塊狀結構(4.8.3.1節)。
大括號與if, else, for, do, while
語句一塊兒使用,即便只有一條語句(或是空),也應該把大括號寫上。
對於非空塊和塊狀結構,大括號遵循Kernighan和Ritchie風格 (Egyptian brackets):
示例:
return new MyClass() { @Override public void method() { if (condition()) { try { something(); } catch (ProblemException e) { recover(); } } } };
4.8.1節給出了enum類的一些例外。
一個空的塊狀結構裏什麼也不包含,大括號能夠簡潔地寫成{}
,不須要換行。例外:若是它是一個多塊語句的一部分(if/else 或 try/catch/finally) ,即便大括號內沒內容,右大括號也要換行。
示例:
void doNothing() {}
每當開始一個新的塊,縮進增長2個空格,當塊結束時,縮進返回先前的縮進級別。縮進級別適用於代碼和註釋。(見4.1.2節中的代碼示例)
每一個語句後要換行。
一個項目能夠選擇一行80個字符或100個字符的列限制,除了下述例外,任何一行若是超過這個字符數限制,必須自動換行。
例外:
package
和import
語句(見3.2節和3.3節)。術語說明:通常狀況下,一行長代碼爲了不超出列限制(80或100個字符)而被分爲多行,咱們稱之爲自動換行(line-wrapping)。
咱們並無全面,肯定性的準則來決定在每一種狀況下如何自動換行。不少時候,對於同一段代碼會有好幾種有效的自動換行方式。
Tip: 提取方法或局部變量能夠在不換行的狀況下解決代碼過長的問題(是合理縮短命名長度吧)
自動換行的基本準則是:更傾向於在更高的語法級別處斷開。
非賦值運算符
處斷開,那麼在該符號前斷開(好比+,它將位於下一行)。注意:這一點與Google其它語言的編程風格不一樣(如C++和JavaScript)。 這條規則也適用於如下「類運算符」符號:點分隔符(.),類型界限中的&(<T extends Foo & Bar>
),catch塊中的管道符號(catch (FooException | BarException e
)賦值運算符
處斷開,一般的作法是在該符號後斷開(好比=,它與前面的內容留在同一行)。這條規則也適用於foreach
語句中的分號。自動換行時,第一行後的每一行至少比第一行多縮進4個空格(注意:製表符不用於縮進。見2.3.1節)。
當存在連續自動換行時,縮進可能會多縮進不僅4個空格(語法元素存在多級時)。通常而言,兩個連續行使用相同的縮進當且僅當它們開始於同級語法元素。
第4.6.3水平對齊一節中指出,不鼓勵使用可變數目的空格來對齊前面行的符號。
如下狀況須要使用一個空行:
多個連續的空行是容許的,但沒有必要這樣作(咱們也不鼓勵這樣作)。
除了語言需求和其它規則,而且除了文字,註釋和Javadoc用到單個空格,單個ASCII空格也出如今如下幾個地方:
(
)(如if, for catch
等)。}
)(如else, catch
)。{
),兩個例外:
@SomeAnnotation({a, b})
(不使用空格)。String[][] x = foo;
(大括號間沒有空格,見下面的Note)。<T extends Foo & Bar>
)。catch (FooException | BarException e
)。foreach
語句中的分號。, : ;
及右括號()
)後new int[] {5, 6}
和new int[] { 5, 6 }
都是能夠的。Note:這個規則並不要求或禁止一行的開關或結尾須要額外的空格,只對內部空格作要求。
術語說明:水平對齊指的是經過增長可變數量的空格來使某一行的字符與上一行的相應字符對齊。
這是容許的(並且在很多地方能夠看到這樣的代碼),但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的工做而且可能致使更多的合併衝突。
除非做者和reviewer都認爲去掉小括號也不會使代碼被誤解,或是去掉小括號能讓代碼更易於閱讀,不然咱們不該該去掉小括號。 咱們沒有理由假設讀者能記住整個Java運算符優先級表。
枚舉常量間用逗號隔開,換行可選。
沒有方法和文檔的枚舉類可寫成數組初始化的格式:
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
因爲枚舉類也是一個類,所以全部適用於其它類的格式規則也適用於枚舉類。
4.8.2.1 每次只聲明一個變量
不要使用組合聲明,好比int a, b;
。
4.8.2.2 須要時才聲明,並儘快進行初始化
不要在一個代碼塊的開頭把局部變量一次性都聲明瞭(這是c語言的作法),而是在第一次須要使用它時才聲明。 局部變量在聲明時最好就進行初始化,或者聲明後儘快進行初始化。
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[]
。
術語說明: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) { case 1: case 2: prepareOneOrTwo(); // fall through case 3: handleOneTwoOrThree(); break; default: handleLargeNumber(input); }
4.8.4.3 default的狀況要寫出來
每一個switch語句都包含一個default
語句組,即便它什麼代碼也不包含。
註解緊跟在文檔塊後面,應用於類、方法和構造函數,一個註解獨佔一行。這些換行不屬於自動換行(第4.5節,自動換行),所以縮進級別不變。例如:
@Override @Nullable public String getNameIfPresent() { ... }
例外:單個的註解能夠和簽名的第一行出如今同一行。例如:
@Override public int hashCode() { ... }
應用於字段的註解緊隨文檔塊出現,應用於字段的多個註解容許與字段出如今同一行。例如:
@Partial @Mock DataLoader loader;
參數和局部變量註解沒有特定規則。
4.8.6.1 塊註釋風格
塊註釋與其周圍的代碼在同一縮進級別。它們能夠是/* ... */
風格,也能夠是// ...
風格。對於多行的/* ... */
註釋,後續行必須從*
開始, 而且與前一行的*
對齊。如下示例註釋都是OK的。
/* * This is // And so /* Or you can * okay. // is this. * even do this. */ */
註釋不要封閉在由星號或其它字符繪製的框架裏。
Tip:在寫多行註釋時,若是你但願在必要時能從新換行(即註釋像段落風格同樣),那麼使用
/* ... */
。
類和成員的modifiers若是存在,則按Java語言規範中推薦的順序出現。
public protected private abstract static final transient volatile synchronized native strictfp
標識符只能使用ASCII字母和數字,所以每一個有效的標識符名稱都能匹配正則表達式\w+
。
在Google其它編程語言風格中使用的特殊前綴或後綴,如name_
, mName
, s_name
和kName
,在Java編程風格中都再也不使用。
包名所有小寫,連續的單詞只是簡單地鏈接起來,不使用下劃線。
類名都以UpperCamelCase
風格編寫。
類名一般是名詞或名詞短語,接口名稱有時多是形容詞或形容詞短語。如今尚未特定的規則或行之有效的約定來命名註解類型。
測試類的命名以它要測試的類的名稱開始,以Test
結束。例如,HashTest
或HashIntegrationTest
。
方法名都以lowerCamelCase
風格編寫。
方法名一般是動詞或動詞短語。
下劃線可能出如今JUnit測試方法名稱中用以分隔名稱的邏輯組件。一個典型的模式是:test<MethodUnderTest>_<state>
,例如testPop_emptyStack
。 並不存在惟一正確的方式來命名測試方法。
常量名命名模式爲CONSTANT_CASE
,所有字母大寫,用下劃線分隔單詞。那,到底什麼算是一個常量?
每一個常量都是一個靜態final字段,但不是全部靜態final字段都是常量。在決定一個字段是不是一個常量時, 考慮它是否真的感受像是一個常量。例如,若是任何一個該實例的觀測狀態是可變的,則它幾乎確定不會是一個常量。 只是永遠不打算
改變對象通常是不夠的,它要真的一直不變才能將它示爲常量。
// 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"};
這些名字一般是名詞或名詞短語。
很是量字段名以lowerCamelCase
風格編寫。
這些名字一般是名詞或名詞短語。
參數名以lowerCamelCase
風格編寫。
參數應該避免用單個字符命名。
局部變量名以lowerCamelCase
風格編寫,比起其它類型的名稱,局部變量名能夠有更爲寬鬆的縮寫。
雖然縮寫更寬鬆,但仍是要避免用單字符進行命名,除了臨時變量和循環變量。
即便局部變量是final和不可改變的,也不該該把它示爲常量,天然也不能用常量的規則去命名它。
類型變量可用如下兩種風格之一進行命名:
駝峯式命名法分大駝峯式命名法(UpperCamelCase
)和小駝峯式命名法(lowerCamelCase
)。 有時,咱們有不僅一種合理的方式將一個英語詞組轉換成駝峯形式,如縮略語或不尋常的結構(例如」IPv6」或」iOS」)。Google指定了如下的轉換方案。
名字從散文形式
(prose form)開始:
示例:
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*
加星號處表示能夠,但不推薦。
Note:在英語中,某些帶有連字符的單詞形式不惟一。例如:」nonempty」和」non-empty」都是正確的,所以方法名
checkNonempty
和checkNonEmpty
也都是正確的。
只要是合法的,就把@Override
註解給用上。
除了下面的例子,對捕獲的異常不作響應是極少正確的。(典型的響應方式是打印日誌,或者若是它被認爲是不可能的,則把它看成一個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
。
Tip:不要使用finalize。若是你非要使用它,請先仔細閱讀和理解Effective Java 第7條款:「Avoid Finalizers」,而後不要使用它。
Javadoc塊的基本格式以下所示:
/** * Multiple lines of Javadoc text are written here, * wrapped normally... */ public int method(String p1) { ... }
或者是如下單行形式:
/** An especially short bit of Javadoc. */
基本格式老是OK的。當整個Javadoc塊能容納於一行時(且沒有Javadoc標記@XXX),可使用單行形式。
空行(即,只包含最左側星號的行)會出如今段落之間和Javadoc標記(@XXX)以前(若是有的話)。 除了第一個段落,每一個段落第一個單詞前都有標籤<p>
,而且它和第一個單詞間沒有空格。
標準的Javadoc標記按如下順序出現:@param
, @return
, @throws
, @deprecated
, 前面這4種標記若是出現,描述都不能爲空。 當描述沒法在一行中容納,連續行須要至少再縮進4個空格。
每一個類或成員的Javadoc以一個簡短的摘要片斷開始。這個片斷是很是重要的,在某些狀況下,它是惟一出現的文本,好比在類和方法索引中。
這只是一個小片斷,能夠是一個名詞短語或動詞短語,但不是一個完整的句子。它不會以A {@code Foo} is a...
或This method returns...
開頭, 它也不會是一個完整的祈使句,如Save the record...
。然而,因爲開頭大寫及被加了標點,它看起來就像是個完整的句子。
Tip:一個常見的錯誤是把簡單的Javadoc寫成
/** @return the customer ID */
,這是不正確的。它應該寫成/** Returns the customer ID. */
。
至少在每一個public類及它的每一個public和protected成員處使用Javadoc,如下是一些例外:
對於簡單明顯的方法如getFoo
,Javadoc是可選的(即,是能夠不寫的)。這種狀況下除了寫「Returns the foo」,確實也沒有什麼值得寫了。
單元測試類中的測試方法多是不言自明的最多見例子了,咱們一般能夠從這些方法的描述性命名中知道它是幹什麼的,所以不須要額外的文檔說明。
Tip:若是有一些相關信息是須要讀者瞭解的,那麼以上的例外不該做爲忽視這些信息的理由。例如,對於方法名
getCanonicalName
, 就不該該忽視文檔說明,由於讀者極可能不知道詞語canonical name
指的是什麼。
若是一個方法重寫了超類中的方法,那麼Javadoc並不是必需的。
對於包外不可見的類和方法,若有須要,也是要使用Javadoc的。若是一個註釋是用來定義一個類,方法,字段的總體目的或行爲, 那麼這個註釋應該寫成Javadoc,這樣更統一更友好。
本文檔翻譯自Google Java Style, 譯者@Hawstein。