原文标题:我有一个朋友写出了17种触发NPE的代码!避免这些坑
原文作者:阿里云开发者
冷月清谈:
怜星夜思:
2、在实际开发中,你是如何避免NPE的呢?有哪些好的实践经验可以分享?
3、你认为Java语言在设计上是否存在一些缺陷,导致NPE如此常见?
原文内容
阿里妹导读
1.访问空对象的实例变量或者调用空对象的实例方法
public class Test { public String a;
public String getA() {
return a;
}public static void main(String args) {
Test test = getFromSomeMethod();
//访问属性 NPE
System.out.println(test.a);
//访问方法 NPE
System.out.println(test.getA());
}
private static Test getFromSomeMethod() {
return null;
}
}
2.访问或修改空数组的元素
public class Test {
public static void main(String[] args) {
int[] numbers = getFromSomeMethod();
//访问 NPE
int number = numbers[0];
//修改 NPE
numbers[0] =1;
}
private static int[] getFromSomeMethod() {
return null;
}
}
3.未初始化的对象数组中的元素默认是null
public class Test { private String a;
public String getA() {
return a;
}public static void main(String args) {
Test testArr = new Test[2];
//NPE
testArr[0].getA();
}
}
4.throw一个null 出去
-
代码错误:throw null 可能是代码编写错误或者不完整的异常处理。例如,可能打算抛出一个实际的异常对象,但误写成了 null。
-
测试代码:在单元测试中,有时可能会故意使用throw null , 来确保他们的异常处理代码能够妥善处理意外情况。(不推荐)
public class Test { public static void main(String[] args) { getFromSomeMethod(); }
private static int getFromSomeMethod() {
try {
int a = 1/0;
}catch (Exception e){
//NPE
throw null;
}
return 0;
}
}
5.在null 引用上进行synchronized同步
public class Test { public static void main(String[] args) { Test test = getFromSomeMethod(); //NPE synchronized (test){
}
}
private static Test getFromSomeMethod() {
return null;
}
}
6.在自动拆箱过程中遇到null
public class Test { public static void main(String[] args) { Integer integer = getFromSomeMethod(); //NPE if (integer > 1) {
}
}
private static Integer getFromSomeMethod() {
return null;
}
}
public static void main(String[] args) { getFromSomeMethod();
}
private static int getFromSomeMethod() {
Integer a = null;
// NPE
return a;
}
7.从集合/Map中获取null元素并直接使用
Map<String, String> map = new HashMap<>();
String value = map.get("key");
//NPE
int length = value.length();
8.方法链调用中上一步骤返回null
Test test = new Test().getA().getB().getC();
9.枚举的valueOf方法使用null
Enum enum = Enum.valueOf(null);
10.集合操作不支持null元素
Set<String> set = new TreeSet<>();
set.add(null);
11.多线程环境中无适当同步可能导致不一致状态
public class Test implements Runnable { private static String sharedResource;
public void run() {
sharedResource = “sharedResource”;
}
public static void main(String args) throws InterruptedException {
Thread thread = new Thread(new Test());
thread.start();
// 在多线程环境中,如果没有适当的同步,这里可能导致NPE
//thread.join();
System.out.println(sharedResource.length());
}
}
12.依赖注入:注入的对象为null
@Autowired(required = false)
private SomeService service;
13.Lambda表达式或方法引用中目标引用为null
Test test = null;
Consumer<Test> todoSomething = test::someMethod;
14.Stream API处理时遇到null元素
list = Arrays.asList("a", null);
> lengths = list.stream().map(String::length).collect(Collectors.toList());
正例
List<String> list = Arrays.asList("a", null);
List<Integer> lengths = list.stream()
.filter(Objects::nonNull) // 过滤null
.map(String::length).collect(Collectors.toList());
15.使用增强for循环遍历集合时,没有判空
List<String> list = null;
for (String item : list) { }
16.在Junit中使用Mockito时,
错误地使用any()匹配基本数据类型参数
when(service.doSomething(any())).thenReturn("Success");
// service.doSomething(int a)
when(service.doSomething(anyInt())).thenReturn("Success");
// service.doSomething(int a)
17.Optional类的正确使用
Optional<String> optional = Optional.of(null);
Optional<String> optional = Optional.ofNullable(null);