在日常Java开发中,NullPointerException(NPE)是我们最常遇到的运行时异常之一。特别是字符串操作时,一不小心就会掉进NPE的陷阱。今天就来彻底剖析这些隐藏的坑点,让你的代码更加健壮!
🔥 最经典的陷阱:a.equals(b)
String a = null;
String b = "hello";
// 这是NPE的经典场景!
a.equals(b); // 抛出 NullPointerException
真相揭秘:
-
a可以为null,但调用方法时会抛出NPE -
b可以为null,通常返回false(前提是a不为null)
安全写法:
// 方法1:让常量在前(推荐)
"hello".equals(a); // 安全,a为null时返回false
// 方法2:使用Objects.equals(最安全)
Objects.equals(a, b); // 两者都为null时返回true
// 方法3:显式null检查
if (a != null) {
a.equals(b);
}
💥 更大的陷阱:a.contains(b)
你以为equals已经很坑了?contains更是坑中之王!
String a = null;
String b = "hello";
a.contains(b); // NPE!
String c = "hello";
String d = null;
c.contains(d); // 还是NPE!
残酷真相:
-
a不能为null → NPE -
b不能为null → NPE -
两个参数都不能为null!
安全方案:
// 自定义安全方法
public static boolean safeContains(String str, String searchStr) {
return str != null && searchStr != null && str.contains(searchStr);
}
// 使用工具类
StringUtils.contains(a, b); // Apache Commons Lang
🚨 字符串操作中的NPE地雷阵
下面这些方法,只要调用者为null,统统NPE!
比较相关
String str = null;
str.compareTo("abc"); // 💥 NPE
str.compareToIgnoreCase("abc"); // 💥 NPE
str.contentEquals("abc"); // 💥 NPE
查找相关
str.indexOf("a"); // 💥 NPE
str.lastIndexOf("a"); // 💥 NPE
str.startsWith("a"); // 💥 NPE
str.endsWith("a"); // 💥 NPE
操作相关
str.substring(1); // 💥 NPE
str.charAt(0); // 💥 NPE
str.length(); // 💥 NPE
str.trim(); // 💥 NPE
str.toUpperCase(); // 💥 NPE
正则相关
str.matches("regex"); // 💥 NPE
str.replaceAll("a", "b"); // 💥 NPE
str.split(","); // 💥 NPE
空检查(讽刺吧?)
str.isEmpty(); // 💥 NPE
str.isBlank(); // 💥 NPE
🛡️ 全方位防御方案
方案1:Objects工具类(JDK原生)
import java.util.Objects;
Objects.equals(a, b); // 比较安全
Objects.toString(str, "default"); // 转字符串安全
方案2:Apache Commons Lang
import org.apache.commons.lang3.StringUtils;
StringUtils.equals(a, b); // 比较安全
StringUtils.contains(a, b); // 包含检查安全
StringUtils.isEmpty(a); // 空检查安全
StringUtils.isBlank(a); // 空白检查安全
方案3:防御性编程模式
// 三元运算符
String safeStr = (str != null) ? str : "";
boolean result = safeStr.contains("abc");
// Optional优雅处理
Optional.ofNullable(str)
.map(s -> s.contains("abc"))
.orElse(false);
// 提前返回
if (str == null) {
return false; // 或抛出业务异常
}
return str.contains("abc");
方案4:静态代码分析工具
-
SonarQube:检测潜在的NPE风险
-
SpotBugs:静态分析找出NPE问题
-
IDEA Inspections:IDE自动提示
📊 最佳实践总结
| 场景 | 危险写法 | 安全写法 |
|---|---|---|
| 字符串比较 | a.equals(b) | Objects.equals(a, b) |
| 包含检查 | a.contains(b) | StringUtils.contains(a, b) |
| 空检查 | a.isEmpty() | StringUtils.isEmpty(a) |
| 方法调用 | a.length() | Optional.ofNullable(a).map(String::length) |
💡 终极建议
-
养成习惯:总是考虑参数为null的情况
-
使用工具:优先选择null安全的工具类
-
代码审查:将NPE风险纳入代码审查清单
-
单元测试:覆盖null边界情况的测试用例
记住:在Java世界里,唯一不会抛出NPE的字符串方法,就是你没有在null上调用的那个方法!
思考题:你的项目中还有哪些隐藏的NPE陷阱?欢迎在评论区分享交流!
评论