英文版本
中文版本
轉(zhuǎn)自CSDN https://blog.csdn.net/lawliet3389/article/details/54341337
引言
本文為Google java編程語言編碼規(guī)范的完整定義。依照此規(guī)范編寫的Java源碼文件可以被稱為Google Style。
和其他編程規(guī)范指南一樣,規(guī)范不僅包括代碼的結構美學,也包括了其他一些業(yè)界約定俗成的公約和普遍采用的標準。本文檔中的規(guī)范基本都是業(yè)界已經(jīng)達成共識的標準,我們盡量避免去定義那些還存在爭議的地方。
1.1 術語說明
在本文中(除非另有說明):
- 類(Class):用于標識是一個普通類(Class)、枚舉類(enum)、接口(interface)或注解類型(@interface)。
- 成員(member of a class):表示嵌套類、屬性、方法或構造方法;即除了初始化和注釋之外的類的所有頂級內(nèi)容。
- 注釋 (comment )總是指implementation comments(實現(xiàn)注釋)。我們不使用“文檔注釋”這樣的說法,而會直接說“Javadoc”。
其它術語將在文檔中單獨說明。
1.2 指南說明
本文檔中的代碼并不一定符合所有規(guī)范。即使這些代碼遵循Google Style,但這不是唯一的代碼規(guī)范。例子中可選的格式風格也不應該作為強制執(zhí)行的規(guī)范。
2源碼文件基礎
2.1 文件名
源碼文件名由它所包含的頂級class的類名(區(qū)分大小寫),加上.java擴展名組成。
2.2 文件編碼:UTF-8
源碼文件編碼應為UTF-8。
2.3 特殊字符
2.3.1 空格字符
除了換行符外,ASCII水平空白字符(0x20)是源碼文件中唯一支持的空格字符。這意味著:
- 字符串和字符文字中的所有其它空格字符都將被轉(zhuǎn)義。
- 制表符(Tab鍵)不用于縮進。
2.3.2 特殊轉(zhuǎn)義字符串
任何需要轉(zhuǎn)義字符串表示的字符(例如\b, \t, \n, \f, \r, \’, \等),采用這種轉(zhuǎn)義字符串的方式表示,而不采用對應字符的八進制數(shù)(例如 \012)或Unicode碼(例如 \u000a)表示。
2.3.3 非ASCII字符
對于其余非ASCII字符,直接使用Unicode字符(例如 ∞),或者使用對應的Unicode碼(例如 \u221e)轉(zhuǎn)義,都是允許的。唯一需要考慮的是,何種方式更能使代碼容易閱讀和理解。
提示:在使用unicode碼轉(zhuǎn)義,或者甚至是有時直接使用unicode字符的時候,添加一點說明注釋將對別人讀懂代碼很有幫助。
例子:
提示:不要因為擔心一些程序無法正常處理ASCII字符而不使用它,從而導致代碼易讀性變差。如果出現(xiàn)這樣的問題,應該由出現(xiàn)問題的程序去解決。
3.源碼文件結構
源碼文件包括,依次是:
- License或者copyright聲明信息(如有)
- 包聲明語句
- import語句
- class類聲明
每個部分之間以一行空行分隔。
3.1 Lincense 或 copyright聲明信息(如有)
如果需要聲明lincense或copyright信息,應該在文件開始時聲明。
3.2 包聲明
包聲明沒有長度限制,單行長度限制規(guī)范,不適用于包聲明。
3.3 import語句
3.3.1 不使用通配符import
不應使用通配符import,不管是不是靜態(tài)導入。
3.3.2 沒有行長度限制
import語句的行,沒有行長度的限制。單行長度限制規(guī)范,不適用于import語句所在行。
3.3.3 順序和空行
import的順序如下:
- 所有靜態(tài)導入(static import)為一組
- 所有非靜態(tài)導入為一組
如果同時存在靜態(tài)導入與非靜態(tài)導入,則以一個空白行分隔,import語句之間沒有其它空行。
每一個組中,import的名稱以ASCII排序顯示。
3.3.4 沒有靜態(tài)導入的類
靜態(tài)導入不能用于靜態(tài)嵌套類。它們可以正常導入。
3.4 類聲明
3.4.1 只聲明唯一一個頂級class
每個源碼文件中只能有一個頂級class。
3.4.2 類成員順序
類成員的順序?qū)Υa的易讀性有很大影響,但是沒有一個統(tǒng)一正確的標準。不同的類可以以不同的方式對其內(nèi)容進行排序。
重要的是,每個class都要按照一定的邏輯規(guī)律排序。當被問及時,能夠解釋清楚為什么這樣排序。例如,新增加的成員方法,不是簡單地放在class代碼最后面,按日期排序不是按邏輯排序。
3.4.2.1 重載:從不分開
當一個類有多個構造函數(shù)或多個同名的方法時,這個函數(shù)要寫在一些,中間不要有其它代碼。
4、格式規(guī)范
術語注:塊狀結構(block-like construct)指類、成員函靈敏和構造函數(shù)的主體。需要注意的是,在后面的4.8.3.1節(jié)中講到的數(shù)組初始化,所有的數(shù)組初始化都可以被 認為是一個塊狀結構(非強制)。
4.1 大括號
4.1.1 在需要的地方使用
大括號用在if,else,for,do,和while等語句。甚至當它的實現(xiàn)為空或者只有一句話時,也要使用。
4.1.2 非空語句塊采用K&R風格
對于非空語句塊,大括號遵循Kernighan和Ritchie的風格:
- 大括號前沒有換行
- 開頭大括號后換行
- 結束大括號前換行
- 如果右括號結束一個語句塊或者函數(shù)體、構造函數(shù)體或者有命名的類體,則需要換行。例如,當右括號后面接else或者逗號時,不應該換行。
例子:
一些例外的情況,將在4.8.1節(jié)講枚舉類型時講到。
4.1.3 空語句塊:使代碼更簡法
一個空的語句塊,可以在大括號開始之后真接接結束大括號,中間不需要空格或換行。但是當一個由幾個語句塊聯(lián)合組成的語句塊時,則需要換行。(例如:if/else 或try/catch/finally)
例子:
反例:
4.2 語句塊的縮進:2空格
每當一個新的語句塊產(chǎn)生,縮進就增加兩個空格。當這個語句塊結束時,縮進恢復到上一層級的縮進格數(shù)。縮進要求對整個語句塊中的代碼和注釋都適用。(例子可參考之前4.1.2節(jié)中的例子)。
4.3 一行最多只有一句代碼
每句代碼的結束都需要換行。
4.4 行長度限制:100
Java代碼的單行限制長度為100個字符。除以下情況,超出此上限的行必須進行換行,如4.5節(jié)所解釋的。
例外:
- 無法遵守的地方(例如:Javadoc中長的URL或長JSNI方法的引用)
- package和import語句(見3.2節(jié) 包聲明和3.3節(jié) import語句)
- 注釋中的命令行指令,可以剪切并粘貼到shell中的
4.5 長行換行
術語說明:當一行代碼按照其他規(guī)范都合法,只是為了避免超出行長度限制而換行時,稱為長行換行。
長行斷行,沒有一個適合所有場景的全面、確定的規(guī)范。但很多相同的情況,我們經(jīng)常使用一些行之有效的斷行方法。
注:將長行封裝為函數(shù),或者使用局部變量的方法,也可以解決一些超出行長度限制的情況。并非一定要斷行。
提示:提取方法或局部變量可以解決該問題,而不需要長行換行。
4.5.1 在何處換行
換行的主要原則是:選擇在更高一級的語法邏輯的地方斷行。其他一些原則如下:
-
當一個非賦值運算的語句斷行時,在運算符號之前斷行。(這與Google的C++規(guī)范和JavaScrip規(guī)范等其他規(guī)范不同)。
這也適用于以下類似運算符的符號:- 點分隔符(.)
- 方法此用中的兩個冒號(::)
- 泛型類的符號(< T extends Foo & Bar>)
- catch塊( catch (FooException | BarException e))
當一個賦值運算語句斷行時,一般在賦值符號之后斷行。但是也可以在之前斷行。
在調(diào)用函數(shù)或者構造函數(shù)需要斷行時,與函數(shù)名相連的左括號要在一行。也就是在左括號之后斷行。
逗號斷行時,要和逗號隔開的前面的語句斷行。也就是在逗號之后斷行。
-
在lambda中,一行不會與箭頭相鄰,除非如果lambda的主體由單個無括號的表達式組成,則可以在箭頭之后立即出現(xiàn)換行。
例子:
這里寫圖片描述
注:換行的主要目的是要清晰的代碼,每行不一定適合最小的限制字符。
4.5.2 斷行的縮進:至少4個字符
當斷行之后,在第一行之后的行,我們叫做延續(xù)行。每一個延續(xù)行在第一行的基礎上至少縮進四個字符。
當原行之后有多個延續(xù)行的情況,縮進可以大于4個字符。如果多個延續(xù)行之間由同樣的語法元素斷行,它們可以采用相同的縮進。
4.6.3節(jié)介紹水平對齊中,解決了使用多個空格與之前行縮進對齊的問題。
4.6 空白空間
4.6.1 垂直空白
單行空行在以下情況使用:
- 類成員間需要空行隔開:例如成員變量、構造函數(shù)、成員函數(shù)、內(nèi)部類、靜態(tài)初始化語句塊(static initializers)、實例初始化語句塊(instance initializers)。
例外:成員變量之間的空白行不是必需的。一般多個成員變量中間的空行,是為了對成員變量做邏輯上的分組。 - 在函數(shù)內(nèi)部,根據(jù)代碼邏輯分組的需要,設置空白行作為間隔。
- 類的第一個成員之前,或者最后一個成員結束之后,用空行間隔。(可選)
- 本文檔中其他部分介紹的需要空行的情況。(例如 3.3節(jié)中的import語句)
單空行時使用多行空行是允許的,但是不要求也不鼓勵。
4.6.2 水平空白
除了語法、其他規(guī)則、詞語分隔、注釋和javadoc外,水平的ASCII空格只在以下情況出現(xiàn):
所有保留的關鍵字與緊接它之后的位于同一行的左括號之間需要用空格隔開。(例如if、for、catch)
所有保留的關鍵字與在它之前的右花括號之間需要空格隔開。(例如else、catch)
-
在左花括號之前都需要空格隔開。只有兩種例外:
@SomeAnnotation({a, b})String[][] x = {{"foo"}}; 所有的二元運算符和三元運算符的兩邊,都需要空格隔開。
逗號、冒號、分號和右括號之后,需要空格隔開。
// 雙斜線開始一行注釋時。雙斜線兩邊都應該用空格隔開。并且可使用多個空格,但是不做強制要求。
變量聲明時,變量類型和變量名之間需要用空格隔開。
初始化一個數(shù)組時,花括號之間可以用空格隔開,也可以不使用。(例如:new int[] {5, 6} 和 new int[] { 5, 6 } 都可以)
注意:這一原則不影響一行開始或者結束時的空格。只針對行內(nèi)部字符之間的隔開。
4.6.3 水平對齊:不做強制要求
術語說明:水平對齊,是指通過添加多個空格,使本行的某一符號與上一行的某一符號上下對齊。
這種對齊是被允許的,但是不會做強制要求。
以下是沒有水平對齊和水平對齊的例子;
提示:水平對齊能夠增加代碼的可讀性,但是增加了未來維護代碼的難度。考慮到維護時只需要改變一行代碼,之前的對齊可以不需要改動。為了對齊,你更有可能改 了一行代碼,同時需要更改附近的好幾行代碼,而這幾行代碼的改動,可能又會引起一些為了保持對齊的代碼改動。那原本這行改動,我們稱之為“爆炸半徑”。這 種改動,在最壞的情況下可能會導致大量的無意義的工作,即使在最好的情況下,也會影響版本歷史信息,減慢代碼review的速度,引起更多merge代碼 沖突的情況。
4.7 分組括號:建議使用
非必須的分組括號只有在編寫代碼者和代碼審核者都認為大家不會因為沒有它而導致代碼理解錯誤的時候,或者它不會使代碼更易理解的時候才能省略。沒有理由認為所有閱讀代碼的人都能記住所有java運算符的優(yōu)先級。
4.8 特殊結構
4.8.1 枚舉類型
在遵循枚舉常量的每個逗號后,換行符是可選的,還允許附加空行(通常只有一個)。如下例子:
就像是數(shù)組的初始化(詳見4.8.3.1節(jié))
枚舉類型也是一種類(Class),因此Class類的其他格式要求,也適用于枚舉類型。
4.8.2 變量聲明
4.8.2.1 每次聲明一個變量
不要采用一個聲明,聲明多個變量。例如 int a, b;
4.8.2.2 當需要時才聲明,盡快完成初始化
局部變量不應該習慣性地放在語句塊的開始處聲明,而應該盡量離它第一次使用的地方最近的地方聲明,以減小它們的使用范圍。
局部變量應該在聲明的時候就進行初始化。如果不能在聲明時初始化,也應該盡快完成初始化。
4.8.3 數(shù)組
4.8.3.1 數(shù)組初始化:可以類似塊代碼處理
所有數(shù)組的初始化,都可以采用和塊代碼相同的格式處理。例如以下格式都是允許的:
4.8.3.2 不能像C風格一樣聲明數(shù)組
方括號應該是變量類型的一部分,因此不應該和變量名放在一起。例如:應該是String[] args,而不是 String args[] 。
4.8.4 switch語句
術語說明:switch語句是指在switch花括號中,包含了一組或多組語句塊。每組語句塊都由一個或多個switch標簽(例如case FOO:或者 default:)打頭。
4.8.4.1 縮進
和其他語句塊一樣,switch花括號之后縮進兩個字符。
每個switch標簽之后,后面緊接的非標簽的新行,按照花括號相同的處理方式縮進兩個字符。在標簽結束后,恢復到之前的縮進,類似花括號結束。
4.8.4.2 繼續(xù)向下執(zhí)行的注釋
在 switch語句中,每個標簽對應的代碼執(zhí)行完后,都應該通過語句結束(例如:break、continue、return 或拋出異常),否則應該通過注釋說明,代碼需要繼續(xù)向下執(zhí)行下一個標簽的代碼。注釋說明文字只要能說明代碼需要繼續(xù)往下執(zhí)行都可以(通常是 //fall through)。這個注釋在最后一個標簽之后不需要注釋。例如:
4.8.4.3 default標簽需要顯式聲明
每個switch語句中,都需要顯式聲明default標簽。即使沒有任何代碼也需要顯示聲明。
4.8.5 Annotations
Annotations應用到類、函數(shù)或者構造函數(shù)時,應緊接javadoc之后。每一行只有一個Annotations。
Annotations所在行不受行長度限制,也不需要增加縮進。例如:
例外情況:
如果Annotations只有一個,并且不帶參數(shù)。則它可以和類或方法名放在同一行。例如:
Annotations應用到成員變量時,也是緊接javadoc之后。不同的是,多個annotations可以放在同一行。例如:
對于參數(shù)或者局部變量使用Annotations的情況,沒有特定的規(guī)范。
4.8.6 注釋
4.8.6.1 語句塊的注釋風格
注釋的縮進與它所注釋的代碼縮進相同。可以采用 /* / 進行注釋,也可以用 // 進行注釋。當使用 /*/ 進行多行注釋時,每一行都應該以 * 開始, 并且 * 應該上下對齊。
例如:
多行注釋時,如果你希望集成開發(fā)環(huán)境能自動對齊注釋,你應該使用 /**/, //一般不會自動對齊。
4.8.7 修飾符
多個類和成員變量的修飾符,按Java Lauguage Specification中介紹的先后順序排序。具體是:
4.8.8 數(shù)字文字
long 值整型常量使用大寫L后綴,從來沒有小寫(避免與數(shù)字1混淆)。例如:3000000000L而非3000000000l。
5、命名
5.1 適用于所有命名標識符的通用規(guī)范
標示符只應該使用ASCII字母、數(shù)字和下劃線,字母大小寫敏感。因此所有的標示符,都應該能匹配正則表達式 \w+ 。
Google Style中,標示符不需要使用特殊的前綴或后綴,例如:name_, mName, s_name 和 kName。
5.2 不同類型的標示符規(guī)范
5.2.1 包名
包名全部用小寫字母,通過 . 將各級連在一起。不應該使用下劃線。
例如:
com.example.deepspace,而不是com.example.deepSpace或com.example.deep_space 。
5.2.2 類名
類型的命名,采用以大寫字母開頭的大小寫字符間隔的方式(UpperCamelCase)。
class命名一般使用名詞或名詞短語。interface的命名有時也可以使用形容詞或形容詞短語。annotation沒有明確固定的規(guī)范。
測試類的命名,應該以它所測試的類的名字為開頭,并在最后加上Test結尾。例如:HashTest 、 HashIntegrationTest。
5.2.3 方法名
方法命名,采用以小寫字母開頭的大小寫字符間隔的方式(lowerCamelCase)。
方法命名一般使用動詞或者動詞短語。
在JUnit的測試方法中,可以使用下劃線,用來區(qū)分測試邏輯的名字,經(jīng)常使用如下的結構:test_ 。例如:testPop_emptyStack 。
測試方法也可以用其他方式進行命名。
5.2.4 常量名
常量命名,全部使用大寫字符,詞與詞之間用下劃線隔開。(CONSTANCE_CASE)。
常 量是一個靜態(tài)成員變量,但不是所有的靜態(tài)成員變量都是常量。在選擇使用常量命名規(guī)則給變量命名時,你需要明確這個變量是否是常量。例如,如果這個變量的狀 態(tài)可以發(fā)生改變,那么這個變量幾乎可以肯定不是常量。只是計劃不會發(fā)生改變的變量不足以成為一個常量。下面是常量和非常量的例子:
常量一般使用名詞或者名詞短語命名。
5.2.5 非常量的成員變量名
非常量的成員變量命名(包括靜態(tài)變量和非靜態(tài)變量),采用lowerCamelCase命名。
一般使用名詞或名詞短語。
5.2.6 參數(shù)名
參數(shù)命名采用lowerCamelCase命名。
應該避免使用一個字符作為參數(shù)的命名方式。
5.2.7 局部變量名
局部變量采用lowerCamelCase命名。它相對于其他類型的命名,可以采用更簡短寬松的方式。
但即使如此,也應該盡量避免采用單個字母進行命名的情況,除了在循環(huán)體內(nèi)使用的臨時變量。
即使局部變量是final、不可改變的,它也不能被認為是常量,也不應該采用常量的命名方式去命名。
5.2.8 類型名
類型名有兩種命名方式:
- 單獨一個大寫字母,有時后面再跟一個數(shù)字。(例如,E、T、X、T2)。
- 像一般的class命名一樣(見5.2.2節(jié)),再在最后接一個大寫字母。(例如,RequestT、FooBarT)。
5.3 Camel case的定義
有時一些短語被寫成Camel case的時候可以有多種寫法。例如一些縮寫詞匯,或者一些組合詞:IPv6 或者 iOS 等。
為了統(tǒng)一寫法,Google style給出了一種幾乎可以確定為一種的寫法。
- 將字符全部轉(zhuǎn)換為ASCII字符,并且去掉 ’ 等符號。例如,”Müller’s algorithm” 被轉(zhuǎn)換為 “Muellers algorithm” 。
- 將上一步轉(zhuǎn)換的結果拆分成一個一個的詞語。從空格處和從其他剩下的標點符號處劃分。
注意:一些已經(jīng)是Camel case的詞語,也應該在這個時候被拆分。(例如 AdWords 被拆分為 ad words)。但是例如iOS之類的詞語,它其實不是一個Camel case的詞語,而是人們慣例使用的一個詞語,因此不用做拆分。 - 經(jīng)過上面兩部后,先將所有的字母轉(zhuǎn)換為小寫,再把每個詞語的第一個字母轉(zhuǎn)換為大寫。
- 最后,將所有詞語連在一起,形成一個標示符。
注意:詞語原來的大小寫規(guī)則,應該被完全忽略。以下是一些例子:
- 號表示可以接受,但是不建議使用。
提示:有些詞語在英文中,可以用 - 連接使用,也可以不使用 - 直接使用。例如 “nonempty”和 “non-empty”都是可以的。因此,方法名字為checkNonempty 或者checkNonEmpty 都是可以的。
6、編程實踐
6.1 @Override 都應該使用
@Override annotations只要是符合語法的,都應該使用。
例外:當父類方法是@Deparecated時可省略@Override
6.2 異常捕獲 不應該被忽略
一般情況下,catch住的異常不應該被忽略,而是都需要做適當?shù)奶幚?。例如將錯誤日志打印出來,或者如果認為這種異常不會發(fā)生,則應該作為斷言異常重新拋出。
如果這個catch住的異常確實不需要任何處理,也應該通過注釋做出說明。例如:
例外:在測試類里,有時會針對方法是否會拋出指定的異常,這樣的異常是可以被忽略的。但是這個異常通常需要命名為: expected。例如:
6.3 靜態(tài)成員的訪問:應該通過類,而不是對象
當一個靜態(tài)成員被訪問時,應該通過class名去訪問,而不應該使用這個class的具體實例對象。例如:
6.4 不使用Finalizers 方法
重載Object的finalize方法是非常非常罕見的。
注:不應該使用這以方法。如果你認為你必須使用,請先仔細閱讀并理解 Effective Java 第七條 “Avoid Finalizers”。然后不要使用它。
7、Javadoc
7.1 格式規(guī)范
7.1.1 通用格式
最基本的javadoc的通用格式如下例:
或者為單行格式:
通用格式在任何時候使用都是可以的。當javadoc塊只有一行時,可以使用單行格式來替代通用格式。
7.1.2 段落
空白行:是指javadoc中,上下兩個段落之間只有上下對齊的 * 字符的行。每個段落的第一行在第一個字符之前,有一個
標簽,并且之后不要有任何空格。
7.1.3 @從句
所有標準的@從句,應該按照如下的順序添加:@param、@return、@throws、@deprecated。并且這四種@從句,不應該出現(xiàn)在一個沒有描述的Javadoc塊中。
當@從句無法在一行寫完時,應該斷行。延續(xù)行在第一行的@字符的位置,縮進至少4個字符單位。
7.2 摘要片段
每個類或者成員的javadoc,都是由一個摘要片段開始的。這個片段非常重要。因為它是類或者方法在使用時唯一能看到的文本說明。
主要摘要只是一個片段,應該是一個名詞短語或者動詞短語,而不應該是一個完整的句子。但是它應該像一個完整的句子一樣使用標點符號。
注意:一種常見的錯誤是以這種形式使用javadoc:/** @return the customer ID* /.這是不對的。應該改為:/** Returns the customer ID.* /.
7.3 何處應該使用Javadoc
至少,Javadoc應該應用于所有的public類、public和protected的成員變量和方法。和少量例外的情況。例外情況如下。
7.3.1 例外:方法本身已經(jīng)足夠說明的情況
當方法本身很顯而易見時,可以不需要javadoc。例如:getFoo。沒有必要加上javadoc說明“Returns the foo”。
單元測試中的方法基本都能通過方法名,顯而易見地知道方法的作用。因此不需要增加javadoc。
注 意:有時候不應該引用此例外,來省略一些用戶需要知道的信息。例如:getCannicalName 。當大部分代碼閱讀者不知道canonical name是什么意思時,不應該省略Javadoc,認為只能寫/** Returns the canonical name.* / 。
7.3.2 例外:重載方法
重載方法有時不需要再寫Javadoc。
7.3.4 非必需的Javadoc
一些在包外不可見的class和成員變量或方法,根據(jù)需要,也可以使用javadoc。
當一個注釋用以說明這個類、變量或者方法的總體目標或行為時,該注釋應使用Javadoc(使用/**)
</article>
</main>