精通 Java 字串比較:了解 “==”、equals()、compareTo() 的差異與最佳實踐

1. 介紹

為什麼在 Java 中字串比較很重要?

在 Java 程式設計中,字串被廣泛使用於各種情境。檢查使用者名稱、驗證表單輸入、以及驗證 API 回應,都需要進行字串比較。
此時,「如何正確比較字串」 是初學者常見的卡關點。尤其是未能了解 == 運算子與 equals() 方法之差異,會導致 意外的錯誤

不了解 “==” 與 “equals” 差異的危險

請參考以下程式碼:

String a = "apple";
String b = new String("apple");

System.out.println(a == b);       // result: false
System.out.println(a.equals(b));  // result: true

許多人對此輸出感到驚訝。即使字串內容相同,== 仍回傳 false,而 equals() 回傳 true。 這是因為 Java 將字串視為參考型別,== 會比較參考位址。
了解正確的字串比較方式直接影響程式的可靠性與可讀性。若能正確掌握,便能在錯誤發生前就加以防止。

本文將學到什麼

本文將從基礎到實務應用說明 Java 的字串比較,並解答以下問題:

  • ==equals() 有何差異?
  • 如何在比較字串時忽略大小寫?
  • 如何進行字典序(字母順序)比較?
  • 在與 null 比較時,如何避免例外?

透過實務範例,你將對 正確的字串比較實踐 有扎實的認識。

2. Java 中字串的基礎

字串是參考型別

在 Java 中,String 類型不是原始型別(如 intboolean),而是 參考型別String 變數不會直接儲存字元本身,而是 指向儲存在堆積記憶體中的物件的參考
例如:

String a = "hello";
String b = "hello";

ab 可能指向相同的 "hello" 字面值,這是因為 Java 的 字串常值化(string interning) 機制。

字面值字串與 new String() 的差異

Java 會透過重複使用相同的參考來最佳化字面值字串:

String s1 = "apple";
String s2 = "apple";
System.out.println(s1 == s2); // true (same literal, interned)

然而,使用 new 總是會建立一個新物件:

String s3 = new String("apple");
System.out.println(s1 == s3); // false (different references)
System.out.println(s1.equals(s3)); // true (same content)

因此,== 檢查的是 參考,而 equals() 檢查的是 內容

字串是不可變的

另一個重要特性是 String不可變(immutable)。字串一旦建立後就無法更改。

String original = "hello";
original = original + " world";

這會產生一個新的 String 物件,而不是修改原本的字串。

3. 比較字串的方法

使用 == 比較參考

== 會比較物件的參考:

String a = "Java";
String b = new String("Java");

System.out.println(a == b); // false

不應 用於內容比較。

使用 equals() 比較內容

equals() 是比較字串內容的正確方式:

String a = "Java";
String b = new String("Java");

System.out.println(a.equals(b)); // true

避免 NullPointerException

String input = null;
System.out.println(input.equals("test")); // Exception!

使用常數在前的寫法:

System.out.println("test".equals(input)); // false, safe

使用 equalsIgnoreCase() 忽略大小寫

String a = "Hello";
String b = "hello";

System.out.println(a.equalsIgnoreCase(b)); // true

使用 compareTo() 進行字典序比較

  • 0 → 相等
  • 負值 → 呼叫者排在前面
  • 正值 → 呼叫者排在後面
    String a = "apple";
    String b = "banana";
    
    System.out.println(a.compareTo(b)); // negative
    

4. 實務範例

使用者登入檢查

String inputUsername = "Naohiro";
String registeredUsername = "naohiro";

if (registeredUsername.equalsIgnoreCase(inputUsername)) {
    System.out.println("Login successful");
} else {
    System.out.println("Username does not match");
}

密碼比較應始終使用 equals(),因為需要區分大小寫。

表單輸入驗證

String selectedOption = request.getParameter("plan");

if ("premium".equals(selectedOption)) {
    System.out.println("Premium plan selected.");
} else {
    System.out.println("Other plan selected.");
}

使用多個字串檢查的分支邏輯

String cmd = args[0];

if ("start".equals(cmd)) {
    startApp();
} else if ("stop".equals(cmd)) {
    stopApp();
} else {
    System.out.println("Invalid command");
}
switch (cmd) {
    case "start":
        startApp();
        break;
    case "stop":
        stopApp();
        break;
    default:
        System.out.println("Unknown command");
}

安全處理 null

String keyword = null;

if ("search".equals(keyword)) {
    System.out.println("Searching...");
}

5. 效能與最佳化

字串比較的成本

equals()compareTo() 會在內部比較字元。對於長字串或重複比較,可能會影響效能。

使用 String.intern() 以提升效能

String a = new String("hello").intern();
String b = "hello";

System.out.println(a == b); // true

僅在必要時使用,以避免記憶體壓力。

equalsIgnoreCase() 的效能影響

String input = userInput.toLowerCase();
if ("admin".equals(input)) {
    // fast comparison
}

使用 StringBuilder / StringBuffer

StringBuilder sb = new StringBuilder();
sb.append("user_");
sb.append("123");

String result = sb.toString();

if (result.equals("user_123")) {
    // comparison
}

使用快取或映射減少比較

Map<String, Runnable> commandMap = new HashMap<>();
commandMap.put("start", () -> startApp());
commandMap.put("stop", () -> stopApp());

Runnable action = commandMap.get(inputCommand);
if (action != null) {
    action.run();
}

6. 常見問題

Q1. == 與 equals() 有何差異?

A.

  • == 比較參考
  • equals() 比較字串內容

Q2. 為何當變數為 null 時 equals() 會拋出錯誤?

String input = null;
input.equals("test"); // Exception

使用常數在前的比較方式:

"test".equals(input);

Q3. 如何在比較字串時忽略大小寫?

stringA.equalsIgnoreCase(stringB);

Q4. 如何比較字母順序?

a.compareTo(b);

7. 結論

正確選擇比較方法很重要

因為 String 是參考型別,錯誤的比較常會導致意外行為。了解 ==equals() 的差異是必備知識。

檢查清單

  • ==:比較參考
  • equals():比較內容
  • equalsIgnoreCase():忽略大小寫
  • compareTo():字典順序
  • "constant".equals(variable):null 安全
  • 針對大量比較使用 intern() 或快取

實用且必備的知識

字串比較出現在登入驗證、表單驗證、資料庫操作、分支邏輯以及日常許多任務中。掌握正確的技巧有助於撰寫更安全、更可靠的程式碼。 在使用 Java 處理字串時,請將本指南作為參考。