Published on

Google Java Style Guide翻譯及重點整理

Authors
  • avatar
    Name
    Ed Li
    X

導論:

  • 目標明確性: 此文件定義了 Google 對 Java 程式碼的完整編碼標準。若 Java 原始碼符合此指南中的規則,則視為「Google 風格」。
  • 規範重點: 文件著重於必須嚴格遵守的規則,而非提供彈性的建議,避免無法由人或工具強制執行的條款。
  • **術語定義:**class: 包含「一般」類別、列舉類別、介面或註解類型 (@interface)。
  • member: 指的是類別中巢狀類別、欄位、方法或建構子,但不包含初始化器和註解。
  • comment: 指的是「實作」註解,不使用「文件註解」一詞,而使用「Javadoc」一詞。
  • 範例非規範: 文件中的程式碼範例僅為示範,可能不是唯一的程式碼風格。

原始碼檔案基本原則:

  • 檔案命名: 原始碼檔案名稱應與其包含的頂層類別名稱(且只有一個)相同,並加上 .java 副檔名。
  • 檔案編碼: 原始碼檔案必須使用 UTF-8 編碼。
  • 特殊字元:
  • 空白字元: 原始碼檔案中除了換行符號外,ASCII 水平空格字元 (0x20) 是唯一允許出現的空白字元。這意味著:
  • 字串和字元常值中的其他空白字元必須使用跳脫字元。
  • 禁止使用 Tab 字元進行縮排。
  • 跳脫字元: 對於擁有特殊跳脫字元的字元 (\b, \t, \n, \f, \r, \", \' 和 \\),應使用跳脫字元而非八進制或 Unicode 跳脫字元。
  • 非 ASCII 字元: 針對其他非 ASCII 字元,可以使用實際的 Unicode 字元或對應的 Unicode 跳脫字元。選擇的標準是「哪個方法更容易閱讀和理解」,但強烈不建議在字串常值和註解之外使用 Unicode 跳脫字元。
  • 提示: 使用 Unicode 跳脫字元時,或在實際使用 Unicode 字元時,加上解釋性註解會很有幫助。
  • 提示: 不要因為擔心某些程式可能無法正確處理非 ASCII 字元,而降低程式碼的可讀性。若發生問題,該程式有 錯誤 且必須 修正
 // 範例  
 String unitAbbrev \= "μs"; // 最佳:即使沒有註解也很清楚  
 String unitAbbrev \= "\\u03bcs"; // "μs" // 允許,但沒理由這樣做  
 String unitAbbrev \= "\\u03bcs"; // Greek letter mu, "s" // 允許,但很笨拙且容易出錯  
 String unitAbbrev \= "\\u03bcs"; // 糟糕:讀者不知道這是什麼  
 return '\\ufeff' \+ content; // byte order mark // 良好:針對不可列印字元使用跳脫字元,並在必要時加上註解

原始碼檔案結構:

  • 結構順序: 原始碼檔案應按照以下順序排列:
  • 授權或版權資訊(若有)。
  • package 宣告。
  • import 宣告。
  • 剛好一個 頂層類別。
  • 分隔: 各個區塊之間用 一個空行 分隔。
  • package 宣告: package 宣告 不得換行,且不適用 100 個字元的欄位限制。
  • import 宣告:
  • 禁止使用萬用字元 import
  • import 宣告 不得換行,且不適用 100 個字元的欄位限制。
  • **順序和間距:**所有靜態 import 在單一區塊中。
  • 所有非靜態 import 在單一區塊中。
  • 靜態和非靜態 import 之間使用一個空行分隔。
  • 區塊內按 ASCII 排序。
  • 類別不使用靜態 import
  • 類別宣告:
  • 剛好一個頂層類別宣告
  • 類別內容排序: 類別成員和初始化器的排序方式會影響可讀性,但沒有絕對正確的做法,每個類別都應採用 邏輯排序
  • 多載: 同名的方法應連續出現,中間不得穿插其他成員。此規則也適用於建構子,即使修飾詞 (如 static 或 private) 不同。

格式化(斷行跟縮排):

  • 術語定義: 「區塊類結構」指的是類別、方法或建構子的主體。
  • 大括號
  • 強制使用大括號: if、else、for、do 和 while 敘述必須使用大括號,即使程式碼本體是空的或只包含單一敘述。
  • 非空區塊: 非空區塊和區塊類結構使用 Kernighan and Ritchie 風格(「埃及括號」),也就是:
  • 在開啟的大括號前不換行(以下例外)。
  • 在開啟的大括號後換行。
  • 在關閉的大括號前換行。
  • 在關閉的大括號後換行,僅當 關閉的大括號終止敘述或終止方法、建構子或「具名」類別的主體時。
  • 空區塊: 空區塊或區塊類結構可以為 K & R 風格,也可以直接關閉 ( ),除非 它是「多區塊敘述」的一部分(包含多個區塊的敘述:如 if/else 或 try/catch/finally)。
 // 範例  
 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();  
        }  
        {  
            int x \= foo();  
            frob(x);  
        }  
    }  
 }; 
 // 範例  
 void doNothing() {} // 接受  
 void doNothingElse() { }  // 也接受  
   
 try {  
    doSomething();  
 } catch (Exception e) {} // 不接受:多區塊敘述中不能使用簡潔空區塊  
  • 區塊縮排: 每開啟一個區塊或區塊類結構,縮排增加兩個空格。區塊結束時,縮排會返回上一級。縮排層級適用於程式碼和區塊中的註解。
  • 每行一個敘述: 每個敘述後接換行符號。
  • 欄位限制: Java 程式碼的欄位限制為 100 個字元。
  • **例外:**無法遵守欄位限制的程式碼行 (例如 Javadoc 中的長 URL)。
  • package 和 import 宣告。
  • 可複製貼上的註解中的命令列。
  • 非常長的識別符。
  • 換行:
  • 術語定義: 將程式碼分為多行稱為「換行」。
  • 換行原則: 優先在 較高的語法層級 處斷行。
  • **斷行位置:**在非賦值運算子處斷行時,斷行位置應在運算符號 之前
  • 在賦值運算子處斷行時,斷行位置應在符號 之後 (可接受)。
  • 方法或建構子的名稱應與其後面的開括號 ( 相連。
  • 逗號 , 應與其前面的語彙單元相連。
  • lambda 中的箭頭不得斷行。
  • 縮排: 換行後的每一行(「續行」)應從原始行至少縮排 4 個空格。
 // 範例  
 MyLambda\<String, Long, Object\> lambda \= (String label, Long value, Object obj) \-\> { ... };  
 Predicate\<String\> predicate \= str \-\> longExpressionInvolving(str); 
  • 空白字元:
  • 垂直空白: 單一空行通常會出現在以下位置:
  • 類別中連續的成員或初始化器之間。
  • 其他章節規範的地方 (例如:檔案結構、import 宣告)。
  • 改善程式碼可讀性的地方。
  • 水平空白: 除了程式語言或風格規則要求的空格外,以下位置 出現單一 ASCII 空格:
  • 在保留字和後面的開括號之間。
  • 在保留字和前面的關閉大括號之間。
  • 在任何開括號 { 前。
  • 在二元或三元運算子的兩側。
  • 在 ,:; 或型態轉換的關閉括號 ) 之後。
  • 在雙斜線 // 開始的註解之前。
  • 在雙斜線 // 開始的註解與註解文字之間。
  • 在宣告的型態和變數之間。
  • 在陣列初始化器的括號內 (可選)。
  • 在型態註解和 [] 或 ... 之間。
  • 水平對齊: 不強制 使用水平對齊,但允許使用。
 // 範例  
 private int x; // 這樣很好  
 private Color color; // 也這樣很好  
   
 private int x;  // 允許,但未來的編輯  
 private Color color;  // 可能會讓它不對齊
  • 群組括號: 除非作者和審查者都認為不使用括號不會造成誤解,否則建議使用。
  • 特定結構:
  • 列舉類別: 列舉常數後的逗號可選換行,也允許空行。列舉類別可以使用類似陣列初始化器的格式。
  • 變數宣告:一行一個變數宣告
  • 需要時再宣告: 局部變數應在首次使用的地方附近宣告。
  • 陣列:陣列初始化器: 可以選擇視為「區塊類結構」。
  • 不使用 C 風格的陣列宣告: 使用 String[] args,而非 String args[]。
  • switch 敘述:縮排: switch 區塊的內容與其他區塊一樣縮排 +2。
  • case 縮排: case 標籤後換行,縮排層級增加 +2。
  • fall-through: switch 區塊中的每個 statement 群組都應該以 break、continue、return 或拋出例外來結束,或者以註解標示會繼續執行到下一個 statement 群組。
  • default 標籤: 每個 switch 敘述都應包含 default 標籤,即使它不包含任何程式碼。
  • 註解:型態使用註解: 型態使用註解應出現在被註解型態之前。
  • 類別註解: 類別註解應出現在文件區塊之後,且每個註解都應該在單獨一行上。
  • 方法和建構子註解: 方法和建構子註解的規則與類別註解相同。
  • 欄位註解: 欄位註解應出現在文件區塊之後,但可以在同一行上列出多個註解。
  • 參數和局部變數註解: 除了型態使用註解,對參數和局部變數的註解沒有特殊格式化規則。
  • 註解:區塊註解: 區塊註解縮排應與周圍程式碼相同。可以使用 /* ... */ 或 // ... 風格。
 // 範例  
 switch (input) {  
   case 1:  
   case 2:  
     prepareOneOrTwo();  
      // fall through  
   case 3:  
     handleOneTwoOrThree();  
     break;  
   default:  
     handleLargeNumber(input);  
 }  
  • 修飾詞: 類別和成員修飾詞應按照 Java 語言規範建議的順序出現。
  • 數值常值: long 型別的整數常值使用大寫 L 字尾,永遠不使用小寫 (避免與數字 1 混淆)。

命名規則:

  • 通用規則: 識別符只能使用 ASCII 字母和數字,少數情況下可以使用底線。
  • 識別符類型規則:
  • 套件名稱: 套件名稱僅使用小寫字母和數字,不使用底線。
  • 類別名稱: 類別名稱使用 UpperCamelCase (大駝峰式命名法)。
  • 方法名稱: 方法名稱使用 lowerCamelCase (小駝峰式命名法)。測試方法可以使用下劃線,每個組成使用 lowerCamelCase。
  • 常數名稱: 常數名稱使用 UPPER_SNAKE_CASE (大寫蛇形命名法)。
  • 非常數欄位名稱: 非常數欄位名稱使用 lowerCamelCase (小駝峰式命名法)。
  • 參數名稱: 參數名稱使用 lowerCamelCase (小駝峰式命名法)。
  • 局部變數名稱: 局部變數名稱使用 lowerCamelCase (小駝峰式命名法)。
  • 型態變數名稱: 型態變數使用單個大寫字母 (如 E, T, X, T2) 或遵循類別名稱格式加上大寫字母 T (如 RequestT, FooBarT)。
  • 駝峰式命名法: 將英文片語轉換為駝峰式命名法時,遵循以下步驟:
  • 將片語轉換為純 ASCII 並移除任何撇號。
  • 依據空格和任何剩餘的標點符號 (通常為連字符) 將結果分為單字。
  • 將所有字元轉換為小寫,然後將:
  • ...每個單字的第一個字元轉換為大寫,產生 大駝峰式命名法
  • ...除了第一個字元外,將每個單字的第一個字元轉換為大寫,產生 小駝峰式命名法
  • 將所有單字串聯成單一識別符。
* // 範例  
 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 \*  
 "Turn on 2SV"   turnOn2sv     turnOn2Sv

編寫程式實作:

  • @Override: 總是使用 @Override 註解標示方法。
  • 捕捉的例外: 一般來說,捕捉例外但不做任何處理是不正確的。若確實不需要採取任何動作,則需要在 catch 區塊中使用註解解釋原因。
  • 例外: 在測試中,若例外名稱為 expected 或以 expected 開頭,則可以忽略例外。
  • 靜態成員: 引用靜態類別成員時,應使用類別名稱,而不是類別類型的參照或表達式。
  • Finalizers: 不使用覆寫的 Object.finalize 方法。

Javadoc:

  • 格式:基本格式: Javadoc 區塊的基本格式如範例所示。
 /**  
 * 多行 Javadoc 文字寫在這裡,  
 * 正常換行...  
 */  
 public int method(String p1) { ... }  
 /** 簡短的 Javadoc。 */
  • 段落: 段落之間使用一個空白行,且在區塊標籤前,除了第一個段落外,其餘段落的第一個字前面要使用 <p> 標籤。
  • 區塊標籤: 區塊標籤應按照 @param, @return, @throws, @deprecated 的順序排列。區塊標籤描述不得為空。若區塊標籤不適合在單行顯示,應從 @ 位置縮排四個 (或更多) 空格。
  • 摘要片段: 每個 Javadoc 區塊都應以簡短的 摘要片段 開始。此片段非常重要,它會出現在類別和方法索引等地方。摘要片段應為名詞或動詞片語,而非完整的句子,並應以大寫字母開頭,並使用句點結尾。
  • Javadoc 使用位置:最低限度: 每個 public 類別、public 或 protected 成員都必須有 Javadoc,除非有例外。
  • 例外: 自我解釋的成員 (如 getFoo()) 可以省略 Javadoc。
  • 例外: 覆寫超類別方法的 Javadoc 可以省略。
  • 非必要 Javadoc: 其他類別和成員可以根據需要和期望使用 Javadoc。當使用實作註解來定義類別或成員的整體用途時,則應改用 Javadoc。

總結:

此Google Java Style Guide文件提供了詳細的規範,用於確保 Java 程式碼的風格一致性,提升程式碼的可讀性和可維護性。透過遵循這些規則,於大型專案中建立一個標準化的程式碼基礎,從而促進合作並減少錯誤。

資料來源:

Google Java Style Guide