java中字符串内容比较必须用equals()而非==,因==比较引用地址;需注意null安全(推荐objects.equals)、忽略大小写用equalsignorecase()、排序用compareto()并考虑locale问题。

Java里不能直接用 == 比较字符串内容是否相等,必须用 equals() 方法——这是最常踩的坑。
为什么 == 不行?它到底在比什么
== 比较的是两个引用是否指向堆内存中的同一个对象,不是比较字符序列是否一致。哪怕两个字符串字面量完全一样,只要不是来自字符串常量池或没被 intern() 过,== 就可能返回 false。
常见错误现象:
-
new String("hello") == "hello"→false -
String a = "abc"; String b = "ab" + "c"; a == b→true(编译期优化进常量池) -
String a = "abc"; String b = "ab"; String c = b + "c"; a == c→false(运行时拼接,不在常量池)
equals() 是标准做法,但要注意 null 安全
String.equals() 会先判空再逐字符比较,语义清晰、安全可靠。但调用方如果是 null,就会抛 NullPointerException。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 优先用
Objects.equals(str1, str2)(Java 7+),自动处理任一参数为null的情况 - 如果必须用
String.equals(),确保左边是非空变量:"abc".equals(str)比str.equals("abc")更安全 - 避免
str1.equals(str2) || (str1 == null && str2 == null)这类手动判空——冗余且易错
忽略大小写的比较:用 equalsIgnoreCase(),别用 toLowerCase().equals()
String.equalsIgnoreCase() 是专为此设计的,内部做了区域敏感处理(比如土耳其语中 I 和 i 的映射不简单),性能也好。
错误做法示例:
-
str1.toLowerCase().equals(str2.toLowerCase())→ 创建两个新字符串,浪费内存和 CPU -
str1.toUpperCase().equals(str2.toUpperCase())→ 同样问题,且某些 locale 下大小写转换不可逆
正确写法:str1.equalsIgnoreCase(str2),简洁、安全、高效。
按字典序比较大小:用 compareTo() 或 compareToIgnoreCase()
需要判断字符串大小关系(比如排序、二分查找)时,String.compareTo() 返回负数、0、正数分别表示小于、等于、大于,符合 Comparable 合约。
注意点:
- 结果不是布尔值,别写成
if (s1.compareTo(s2) == true)—— 编译不过 - 涉及国际化排序时,应改用
Collator.getInstance(),因为compareTo()基于 Unicode 码点,不适用于中文、德语变音等场景 -
compareToIgnoreCase()同样存在 locale 敏感问题,如需稳定行为,显式传入Locale.ROOT
字符串比较看似简单,但 null 处理、大小写策略、locale 行为、性能开销这些点,实际项目里一个没注意就容易埋雷。尤其在条件判断、Map 键、Set 去重等关键路径上,务必确认用的是语义正确的比较方式。










