在日常開發中,str == null、str.equals("")、str.isEmpty() 混用極易導致空指針異常或邏輯漏洞。本文通過內存模型圖解與代碼實測,徹底釐清三者本質區別,給出生產環境推薦寫法。
| 聲明方式 | 引用變量 | 堆內存對象 | 值 | length() |
|---|---|---|---|---|
String a = new String(); | 指向對象 | 新建 String 對象 | 空字符串 "" | 0 |
String b = ""; | 指向常量池對象 | 常量池共享 "" | 空字符串 "" | 0 |
String c = null; | 不指向任何對象 | 無 | 無 | 調用報 NPE |
public class EmptyCheckDemo {
public static void main(String[] args) {
String a = new String(); // 堆中新對象,值為 ""
String b = ""; // 常量池共享對象
String c = null; // 無對象引用
// 1. null 檢查
System.out.println("a != null: " + (a != null)); // true
System.out.println("b != null: " + (b != null)); // true
System.out.println("c == null: " + (c == null)); // true
// 2. == "" 比較 (比較引用地址,不可靠!)
System.out.println("a == \"\": " + (a == "")); // false (不同對象)
System.out.println("b == \"\": " + (b == "")); // true (常量池同一對象)
// c == "" 編譯器提示 dead code,因為 c 確定為 null
// 3. isEmpty() 檢查 (內容長度為 0)
System.out.println("a.isEmpty(): " + a.isEmpty()); // true
System.out.println("b.isEmpty(): " + b.isEmpty()); // true
// c.isEmpty() → 拋出 NullPointerException
}
}
== "" 比較引用,極不推薦equals("") 或 length() == 0length() == 0// 推薦:簡潔、安全、性能好
if (str != null && str.isEmpty()) { ... }
// 或者 Apache Commons Lang / Spring StringUtils
if (StringUtils.isEmpty(str)) { ... } // null 或 "" 返回 true
// 推薦:Spring/StringUtils
if (StringUtils.hasText(str)) { ... } // true: 非null、非空、非空白
// 原生 JDK 11+
if (str != null && !str.isBlank()) { ... } // isBlank() 識別空白字符
@NotBlank(message = "用戶名不能為空")
@Size(max = 20)
private String username;
// Controller 方法
public Result save(@Valid @RequestBody UserDTO dto) { ... }
if (str == "") — 比較引用地址,new String() 會失效。if (str.equals("")) — str 為 null 直接 NPE。if (str.isEmpty()) — str 為 null 直接 NPE。if (str != null && str.isEmpty()) — 標準雙重檢查。StringUtils.isEmpty(str) / StringUtils.hasText(str) — 工具類統一語義。@NotBlank + @Valid — 聲明式校驗,業務代碼零侵入。Benchmark Mode Cnt Score Error Units
EmptyCheck.nullCheck thrpt 10 12.3 ± 0.2 ops/ns
EmptyCheck.lengthCheck thrpt 10 11.8 ± 0.3 ops/ns
EmptyCheck.isEmptyCheck thrpt 10 12.1 ± 0.2 ops/ns
EmptyCheck.stringUtilsEmpty thrpt 10 10.5 ± 0.4 ops/ns (方法調用開銷)
原生 != null && isEmpty() 性能最優,工具類調用可忽略不計。可讀性與正確性優先於微觀性能。
掌握這三者區別,配合工具類或註解校驗,能消除 90% 以上字符串判空相關的線上 Bug。建議團隊統一代碼規約,強制使用 StringUtils 或 @NotBlank。