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

简介: 我有一个朋友,写代码的时候常常遭到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");
//NPE
int length = value.length();

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

image.png

反例

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。


示例

@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()匹配基本数据类型参数

在JUnit4中,使用Mockito框架时,any() 是一个参数匹配器,当与基本数据类型一起使用时,需要使用相应的类型特定的匹配器,例如使用anyInt() 而不是any()。因为any()实际上返回的是null,而null不能自动转换为基本数据类型。

反例

when(service.doSomething(any())).thenReturn("Success");
// service.doSomething(int a)

正例

when(service.doSomething(anyInt())).thenReturn("Success");
// service.doSomething(int a)

17.Optional类的正确使用

Optional类在 Java 8 中被引入,其设计初衷是为了提供一种更优雅的方式来处理可能为Null的值,从而减少空指针异常NPE的发生。


但Optional类设计为减少NPE的可能性,却并不是万能的,比如开发者在使用Optional,不检查是否存在,直接调用Optional.get(),那么会得到一个NoSuchElementException。也仍然存在即使使用了Optional,也可能出现NPE的情况。你看:


反例

Optional<String> optional = Optional.of(null);

正例

Optional<String> optional = Optional.ofNullable(null);


来源|阿里云开发者公众号

作者| 光翟

相关文章
|
存储 算法 数据管理
分布式存储的多副本纠删码简介
分布式存储的多副本纠删码简介
|
存储 SQL 缓存
StarRocks常见面试问题(一)
StarRocks常见面试问题(一)
|
安全 Java 程序员
巧用Optional之优雅规避NPE问题
本文探讨了Java中常见的NullPointerException问题及其解决方案,重点介绍了Optional类的使用。通过实例代码分析,展示了如何用Optional替代传统的空值检查,使代码更简洁、优雅。文章详细讲解了Optional的创建方法(如of、ofNullable、empty)及常用方法(如get、orElse、map、flatMap、filter),并通过实战案例演示了其在实际开发中的应用,帮助开发者有效避免NPE问题,提升代码质量。
336 2
巧用Optional之优雅规避NPE问题
replaceAll 的用法总结
replaceAll 的用法总结
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
2101 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
存储 人工智能 弹性计算
2025年阿里云企业高性能云服务器租用价格与选型详解
随着企业数字化转型,阿里云于2025年推出多款高性能云服务器实例,涵盖计算、通用和内存密集型场景。文章分析了企业选择云服务器的核心要点,包括明确业务需求(如计算密集型任务推荐计算型实例)、性能与架构升级(如第八代实例性能提升20%),以及第九代实例支持AI等高算力需求。同时提供了配置价格参考和成本优化策略,助力企业实现效率与成本的最优平衡。
|
Java 编译器 测试技术
深入探讨:try-catch对Java性能的影响
在Java编程中,异常处理是一个不可或缺的部分。使用`try-catch`块可以捕获和处理异常,防止程序崩溃。然而,关于`try-catch`对性能的影响,开发者们持有不同的观点。本文将深入探讨`try-catch`对Java程序性能的影响,并提供一些最佳实践。
323 5
|
搜索推荐
企业CRM新选择——轻巧强大的阿里云上的Salesforce企业版正式发布!
阿里云与Salesforce合作推出的定制化CRM解决方案——阿里云上的Salesforce CRM CN企业版, 涵盖销售云、服务云及销售服务云三大核心云功能。销售云助力销售团队通过智能化工具提升效率, 如线索管理、预测分析等。服务云CN企业版提供工单管理、自助服务等功能, 改善客户服务体验。结合版则全面覆盖销售与服务需求, 实现业务增长与客户满意度提升。
|
Dubbo Java 应用服务中间件
SpringBoot——SpringBoot集成Dubbo
SpringBoot——SpringBoot集成Dubbo
1835 0
SpringBoot——SpringBoot集成Dubbo
|
设计模式 开发框架 Java
分清 PO、VO、DAO、BO、DTO、POJO 含义
分清 PO、VO、DAO、BO、DTO、POJO 含义
1601 1