../stay-away-from-the-npe
远离 NPE 的经验之谈
Published:
NPE
Null References: The Billion Dollar Mistake
NullPointException (下文以 NPE 代替) 可谓是 Java 开发者最常碰到的异常了, 没有之一. 下文简单分享几点经验来避免业务代码中的 NPE.
知其源
什么情况下会抛出 NPE? Java Doc
调用一个 null 实例的方法
Bean bean = null;
bean.getName(); // NPE
获取或者修改 null 实例的字段
Bean bean = null;
bean.name; // NPE
bean.name="name" // NPE
获取 null 数组的长度
String[] sa = null;
int len = sa.length(); // NPE
获取或者修改 null 数组的元素
String[] sa = null;
String s1 = sa[0]; // NPE
sa[0] = "s1"; // NPE
抛出 null 异常实例
throws null; // NPE
几点经验
针对业务代码的几点经验和建议
集合相关
业务代码不可避免的要与集合打交道, 比如从数据库查一批数据.
建议
- 方法返回空集合(Collections.emptyList 等),而不是null.
- 结果判空使用 CollectionUtils.isEmpty(apache common-lang or spring utils)
字符串
String 和 基础数据类型一样, 代码出现的频率极高.
建议
- 方法返回 null.
- 结果判空使用 Strings.isNullOrEmpty(Guava)
关于各种 DTO 内字段的声明
一律使用对象. 即不使用 (int,char... 等基础类型), 避免自动开装箱导致的 NPE.
普通对象
- 方法返回 null.
- 判空使用 if(xx == null){...}
番外, 关于 Optional
经验证, 个人不推荐使用.
验证场景1, 字段使用 Optional 标明该字段是可能为 null.
Class Bean {
private Integer id;
private Optional<String> name;
}
问题:
- name 可能为 null, 这个 null 需不需要 check ?
- 对调用方不友好. name.ifPresent AND name.get 才能取到真正的 name 值
验证场景2, 取值后使用 Optional 包装.
Optinal.ofNullable(name).map(dosomehting).else(dosomething2)
// vs
if(name == null) {
dosomehting
}else {
dosomething
}
从可读性上来看, 更倾向于历史做法.
Optional 没有实现序列化接口
业务开发大多有 RPC, 以 Dubbo 为例, 接口的返回值内如果有 Optional, 序列化会失败.
小结
针对经常碰到的 NPE 问题, 给出来可行的建议, 并就不建议使用 Optional 做了简单的解释.