程式碼規範是程式設計師的基本功,也是團隊協作的基石。本章涵蓋命名、組織、註釋、聲明等核心主題。

GoToFail 漏洞的教訓#

2014 年,蘋果公司的 SSL/TLS 實作中出現了一個嚴重的安全漏洞,根本原因竟是一個簡單的編碼風格問題:

// 有漏洞的程式碼
if ((error = doSomething()) != 0)
    goto fail;
    goto fail;  // 這行總是執行!
if ((error = doMore()) != 0)
    goto fail;

第二個 goto fail 不在 if 條件內,導致後續驗證被跳過,任何憑證都會被接受。

如果遵循「總是使用大括號」的規範,問題一目了然:

if ((error = doSomething()) != 0) {
    goto fail;
    goto fail;  // 顯然多餘
}

教訓:編碼規範不是繁文縟節,而是防止低級錯誤的防線。

命名原則#

命名的重要性#

「計算機科學只有兩件難事:快取失效和命名。」—— Phil Karlton

好的命名能讓程式碼自我解釋,減少註釋需求。

命名方法#

方法格式適用場景
大駝峰InputStreamJava 類別、介面
小駝峰firstNameJava 方法、變數
蛇形max_valueC 語言、常數
串式background-colorCSS 屬性

Java 命名規範#

// 類別:大駝峰
public class UserService { }

// 方法:小駝峰,動詞開頭
public void calculateTotal() { }

// 變數:小駝峰,名詞
String firstName;
int itemCount;

// 常數:全大寫蛇形
static final int MAX_RETRY_COUNT = 3;

命名三原則#

  1. 準確 - 名副其實,見名知意

    // 差
    int d; // elapsed time in days
    // 好
    int elapsedTimeInDays;

2. **規範** - 遵循語言慣例

   ```java
   // 差:混用命名風格
   String user_name;  // 蛇形
   String firstName;  // 駝峰

   // 好:統一使用駝峰
   String userName;
   String firstName;
  1. 可讀 - 寧長勿短

    // 差
    List<String> lst;
    
    // 好
    List<String> userNames;

> [!TIP]
>
> 取名要做到「信、達、雅」—— 準確、直觀、優美。

## 程式碼組織

### 分塊思維

大腦按「塊」處理資訊。好的程式碼組織讓每個邏輯塊清晰可辨:

```java
// 差:擠在一起
if(firstName!=null&&lastName!=null)

// 好:清晰分塊
if ((firstName != null) && (lastName != null))

空白的運用#

元素用途示例
空格同行內區隔a + b
縮排層級關係4 空格或 2 空格
空行區塊分隔方法之間

一行一行為#

// 差:兩個行為在一行
if (variable != null) variable.doSomething();

// 好:分開兩行
if (variable != null) {
    variable.doSomething();
}

換行原則#

  1. 每行不超過 80-120 字元
  2. 在逗號後換行
  3. 在運算符前換行
  4. 新行與上一行同級表達式對齊
String result = calculateSomething(longParameterOne,
        longParameterTwo, longParameterThree);

String value = longStringOne + longStringTwo
        + longStringThree;

註釋的藝術#

註釋的三個麻煩#

  1. 難以維護 - 註釋不會編譯,容易過時
  2. 成為藉口 - 過度依賴註釋,忽略程式碼本身的可讀性
  3. 容易濫用 - 被用來注釋掉程式碼或寫俏皮話

最好的程式碼不需要註釋。如果需要註釋,說明程式碼還不夠清晰。

三種註釋風格#

1. 版權聲明

/*
 * Copyright (c) 2024, Company Name. All rights reserved.
 */

2. API 文件(Javadoc)

/**
 * 計算兩數之和。
 *
 * @param a 第一個加數
 * @param b 第二個加數
 * @return 兩數之和
 * @throws IllegalArgumentException 如果參數為負數
 */
public int add(int a, int b) { }

3. 實作說明

// 使用二分搜尋提高效能
int index = Collections.binarySearch(list, target);

註釋三原則#

原則說明
準確錯誤的註釋比沒有更糟
必要多餘的註釋浪費閱讀時間
清晰混亂的註釋讓程式碼更亂

不要在程式碼裡保留 TODO、除錯語句或注釋掉的程式碼。

聲明規範#

八項紀律#

  1. 取好名字 - 遵循命名規範

  2. 一行一個聲明 - 便於維護

    // 差
    int width, height;
    
    // 好
    int width;
    int height;

3. **需要時再聲明** - 局部變數靠近使用處
4. **類屬性集中聲明** - 便於查找
5. **聲明時初始化** - 防止遺漏
6. **左括號不單獨成行** - Java 慣例
   ```java
   public void method() {  // 好
       // ...
   }
  1. 小括號緊靠標識符 - method() 而非 method ()
  2. 搜尋最佳化的換行 - 常見搜尋模式放同一行

類的內部結構#

推薦順序:

  1. 類屬性
  2. 構造方法
  3. 工廠方法
  4. 公開方法
  5. 私有方法

Java 註解的使用#

@Override#

重寫的方法必須加上 @Override 註解。

好處:

  • 明確標示這是重寫方法
  • 父類修改時編譯器會報錯
class Student extends Person {
    @Override
    public String getFirstName() {
        return super.getFirstName();
    }
}

@Deprecated#

及時廢棄不合理的 API:

/**
 * @deprecated 使用 {@link #newMethod()} 代替
 */
@Deprecated(since = "2.0", forRemoval = true)
public void oldMethod() { }

@SuppressWarnings#

盡量不要使用 @SuppressWarnings。警告是有價值的資訊。

例外處理#

例外分類#

類型示例處理方式
ErrorOutOfMemoryError不需處理
RuntimeExceptionNullPointerException需記錄在文件
Checked ExceptionIOException必須宣告或捕獲

例外處理原則#

  1. 不要用例外處理正常流程

    // 差
    try {
        checkUserName(name);
    } catch (InvalidNameException e) {
        // 處理無效名稱
    }
    
    // 好
    if (isValidUserName(name)) {
        // 處理有效名稱
    } else {
        // 處理無效名稱
    }

2. **選擇精確的例外類型** - 不要用 `Exception`

3. **提供清晰的例外描述**
   ```java
   throw new IllegalArgumentException(
       "User ID must be positive, but was: " + userId);

檔案組織#

專案結構#

project/
├── README           # 軟體說明
├── COPYRIGHT        # 版權資訊
├── LICENSE          # 授權條款
├── src/             # 原始碼
│   └── com/example/
├── test/            # 測試程式碼
│   └── com/example/
└── docs/            # 文件

原始碼檔案結構#

  1. 版權聲明
  2. package 宣告
  3. import 語句
  4. 類別 Javadoc
  5. 類別宣告
  6. 類別實作
程式碼規範檢查清單

命名

  • 類別使用大駝峰
  • 方法和變數使用小駝峰
  • 常數使用全大寫蛇形
  • 名稱準確表達意圖

格式

  • 統一縮排風格
  • 每行不超過 120 字元
  • if/for/while 總是使用大括號
  • 適當使用空行分隔邏輯塊

註釋

  • 公開 API 有 Javadoc
  • 沒有過時的註釋
  • 沒有注釋掉的程式碼

聲明

  • 一行一個聲明
  • 變數靠近使用處聲明
  • 重寫方法有 @Override

例外

  • 文件記錄所有可能的例外
  • 不用例外處理正常流程
  • 例外訊息清晰明確