字符串比较应优先用 equals() 判内容,== 仅比地址;字面量在池中、new 在堆中,== 易误判;推荐“常量.equals(变量)”写法防 null,IDE 和静态检查可拦截隐患。

字符串比较用 equals() 还是 ==,关键看比的是“内容”还是“对象地址”。多数业务场景要判内容是否相等,必须用 equals();用 == 容易在 null、new 创建、池外字符串等情况下误判,埋下隐蔽逻辑漏洞。
字符串字面量 vs new String():== 的陷阱在哪
Java 中字符串字面量(如 "abc")会进入字符串常量池,相同字面量指向同一内存地址,此时 == 偶尔“碰巧”为 true;但用 new String("abc") 创建的对象一定在堆中,和池中对象地址不同,== 必为 false —— 即使内容完全一样。
-
"hello" == "hello"→ true(同池引用) -
new String("hello") == "hello"→ false(堆 vs 池) -
new String("hello") == new String("hello")→ false(两个不同堆对象)
空指针风险:== 不报错但 equals 会崩?其实相反
很多人误以为 == 更“安全”,其实恰恰相反:== 比较 null 和非 null 字符串不会抛异常,但结果恒为 false;而 str.equals("abc") 在 str 为 null 时直接抛 NullPointerException。这不是缺陷,而是及时暴露问题的信号。
- 推荐写法:
"abc".equals(str)—— 字面量调用,永远不空指针 - 避免写法:
str.equals("abc")—— str 为 null 时崩溃 -
str == null ? false : str.equals("abc")可行但啰嗦,不如前一种简洁健壮
实际业务代码中怎么统一规避隐患
在登录校验、状态码判断、配置值匹配等典型场景,所有字符串内容比对都应强制走 equals(),并优先采用“常量在前”写法。
- 状态判断:
"ACTIVE".equals(user.getStatus()),而非user.getStatus() == "ACTIVE"或user.getStatus().equals("ACTIVE") - API 响应码:
"200".equals(response.getCode()),兼容 null 和 new 出来的字符串 - 配置开关:
"true".equalsIgnoreCase(config.get("enableLog")),顺便忽略大小写
IDE 和静态检查能帮你守住这道线
现代 IDE(IntelliJ / Eclipse)默认会警告 == 比较字符串,SonarQube 等工具也将其列为 bug 级别问题。开启相关检查,并把 String.equals() 写法设为团队编码规范,能从源头拦截 90% 以上相关缺陷。
- IntelliJ 设置路径:Settings → Editor → Inspections → “String comparison using ==” 启用
- Maven 项目可引入 findbugs 或 spotbugs 插件自动扫描
- Code Review 时重点关注 if/else 中字符串比较表达式










