整理 Effective Java 書中 Item 62: Avoid using strings when other types are more appropriate 心得筆記

主旨

String 很好用,但也很容易被濫用。因為輸入資料常常是文字格式,很多人會直接用 String 當作萬用資料型別──
但這會造成型別不清、錯誤率高、效能差,也難以維護。

本篇重點就是:不要把 String 當萬用型別。若有更合適的型別,就該使用更合適的型別。

點出問題:三種常見錯誤用法

1. 拿 String 當作其他值型別(primitive、boolean)

錯誤示範:

String age = "18"; //不應該用 String 存數字
String isActive = "true"; // 用來表示布林值也不對

正確做法:

int age = 18;
boolean isActive = true;

從外部系統輸入進來是文字沒錯,但轉型後才是正確的邏輯建模。


2. 拿 String 當 enum 用

String userRole = "ADMIN"; // 哪天拼錯就爆炸了

正確寫法應該是 enum:

enum Role { ADMIN, USER, GUEST }

Role userRole = Role.ADMIN;

這樣程式碼更安全、IDE 有提示、也能使用 switch


3. 拿 String 表示複合資料(aggregate type)

錯誤示範:

String compoundKey = className + "#" + id; // 粗暴地把資料串起來

缺點:

  • 要解析就得自己切字串
  • 萬一資料中有 # 會爆炸
  • 沒有型別,容易誤用

正確作法:定義一個 class

class CompoundKey {
    private final String className;
    private final String id;

    // 建構子、equals、hashCode、toString 自動產生
}

延伸情境:String 作為 capability(權限/資源鑰匙)

早期 ThreadLocal API 的錯誤設計:

ThreadLocal.set("myKey", value);
ThreadLocal.get("myKey");

問題:

  • 所有 key 是全域共用,可能被人亂用或重複
  • 無法保障獨立性與安全性

改善方式 1:用不可偽造的物件當 key

ThreadLocal.Key myKey = ThreadLocal.getKey();
ThreadLocal.set(myKey, value);

改善方式 2:直接讓 key 本身就是變數

ThreadLocal<String> myLocal = new ThreadLocal<>();
myLocal.set("hello");
String result = myLocal.get();

這就是現在 Java 提供的 java.lang.ThreadLocal<T> 實作。
不只安全,也具備型別檢查,完全不需要硬記 key 字串。


小結:String 不是萬用型別

何時該避免使用 String?

情境正確型別
儲存數值、布林值等基本資料int, float, boolean 等
有固定選項的狀態值enum
多個欄位的複合資料class 結構體
權限、識別符、資源 key專屬物件或封裝型別

結論:別再把 String 當作資料的萬用型別。程式邏輯更清晰、錯誤更少、效能更好。