专栏名称: 阿里开发者
阿里巴巴官方技术号,关于阿里的技术创新均将呈现于此
目录
相关文章推荐
gooood谷德设计网  ·  新加坡圣淘沙名胜世界的感官之旅 ·  2 天前  
archrace  ·  竞赛 | Shift 地标建筑设计大赛 ·  昨天  
药明康德  ·  疾病控制率100%的ADC疗法;潜在“fir ... ·  4 天前  
archrace  ·  Selgascano 将为 2025 ... ·  5 天前  
51好读  ›  专栏  ›  阿里开发者

我有一个朋友写出了17种触发NPE的代码!避免这些坑

阿里开发者  · 公众号  ·  · 2024-02-21 08:30

正文

阿里妹导读


我有一个朋友,写代码的时候常常遭到NPE背刺,痛定思痛,总结了NPE出没的17个场景,哪一个你还没有遇到过?
虽然无法统计出Java程序员写的最多的异常是哪一个,NullPointerException(NPE)它一定会榜上有名。无论是初次涉足编程世界的新手,还是在代码海洋中久经风浪的老鸟,几乎都写过NPE异常。要防范它,不在高超的编码技巧,在细。
我有一个朋友,写代码的时候常常遭到NPE背刺,痛定思痛,总结了NPE出没的17个场景,哪一个你还没有遇到过?

1.访问空对象的实例变量或者调用空对象的实例方法

从其它方法(如远程hsf方法或者从DB)返回的结果,不做控制判断,直接访问变量或者方法,可能会NPE。
反例
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 出去

在Java中,通常不会故意使用 throw null 这种表达,因为它实际上没有任何有用的用途。根据Java语言规范, throw 关键字后面应该跟随一个可抛出的对象(Throwable 类或其子类的实例),而 null 并不是一个可抛出的对象。如果你执行 throw null ,将会得到一个 NPE
猜想可能出现的场景:
  • 代码错误: 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

自动装箱不会遇到 Null 的问题,因为这个过程是把基本类型的值转换成包装类对象,基本类型的值是没有 Null 的。
反例
public class Test {    public static void main(String[] args) {        Integer integer = getFromSomeMethod();        //NPE        if (integer > 1) {                    }    }    private static Integer getFromSomeMethod() {        return null;    }
}
定义方法返回一个int 作为出参,但实际return 一个null,也会NPE。
反例
 public static void main(String[] args) {      getFromSomeMethod();
} private static int getFromSomeMethod() { Integer a = null; // NPE return a; }

7.从集合/Map中获取null元素并直接使用

从集合/map中获取元素并使用时,建议对 Null 进行检查,以避免潜在的NPE,特别是在那些隐式触发自动拆箱的场景中。
反例
Map<String, String> map = new HashMap<>();String value = map.get("key");//NPEint length = value.length();

8.方法链调用中上一步骤返回null

反例
Test test = new Test().getA().getB().getC();

9.枚举的valueOf方法使用null

反例
Enum enum = Enum.valueOf(null);

10.集合操作不支持null元素

HashSet 、LinkedHashSet 都只允许添加一个null。后续无论添加多少null元素,都会被忽视。
TreeSet 不允许添加null值,排序集合依赖元素直接的比较操作,而null元素不能与其它对象进行比较,会抛出 NPE ;
反例
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

required属性为false,启动过程中如果没有找到合适的bean,service 会被设置为null。在调用service的任何方法之前 都需要判断 service是否为null。






请到「今天看啥」查看全文