• Java - NPE(NullPointerException);Optional


    一、NPE(NullPointerException)

    NPE(java.lang.NullPointerException)空指针异常

    (一)NPE容易发生的场景

    1、返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE

    2、数据库的查询结果可能为 null

    3、集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null

    4、远程调用返回对象时,一律要求进行空指针判断,防止 NPE

    5、对于Session中获取的数据,建议进行 NPE检查,避免空指针

    6、级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE

    (二)何减少NPE的发生

    1、遵守代码规范

    一个好的代码规范可以在一定程度上减少错误的发生。这里推荐看阿里巴巴的Java开发手册,现已经更新到泰山版了,可以直接去官网下载来看

    2、使用Optional类

    使用JDK8引入的新特性Optional 类来防止NPE 问题,因为Optional类最主要解决的问题就是NPE

    3、空值检测

    使用if(obj == null)来检测我们需要检测的对象,当检测到Null时,则可以抛出针对性的异常类型

    二、Java 8 Optional 类

    Java 8 引入的一个很有趣的特性是 Optional  类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。

    本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。

    Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此

    以下引自菜鸟教程

    Java 8 Optional 类 | 菜鸟教程

    Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

    Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

    Optional 类的引入很好的解决空指针异常。

    类声明

    以下是一个 java.util.Optional 类的声明:

    public final class Optional extends Object

    类方法

    序号方法 & 描述
    1static Optional empty()

    返回空的 Optional 实例。

    2boolean equals(Object obj)

    判断其他对象是否等于 Optional。

    3Optional filter(Predicate predicate)

    如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。

    4 Optional flatMap(Function> mapper)

    如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional

    5T get()

    如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException

    6int hashCode()

    返回存在值的哈希码,如果值不存在 返回 0。

    7void ifPresent(Consumer consumer)

    如果值存在则使用该值调用 consumer , 否则不做任何事情。

    8boolean isPresent()

    如果值存在则方法会返回true,否则返回 false。

    9Optional map(Function mapper)

    如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。

    10static Optional of(T value)

    返回一个指定非null值的Optional。

    11static Optional ofNullable(T value)

    如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。

    12T orElse(T other)

    如果存在该值,返回值, 否则返回 other。

    13T orElseGet(Supplier other)

    如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。

    14 T orElseThrow(Supplier exceptionSupplier)

    如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

    15String toString()

    返回一个Optional的非空字符串,用来调试

    注意: 这些方法是从 java.lang.Object 类继承来的

    Optional 实例

    我们可以通过以下实例来更好的了解 Optional 类的使用:

    Java8Tester.java 文件

    1. import java.util.Optional;
    2. public class Java8Tester {
    3. public static void main(String args[]){
    4. Java8Tester java8Tester = new Java8Tester();
    5. Integer value1 = null;
    6. Integer value2 = new Integer(10);
    7. // Optional.ofNullable - 允许传递为 null 参数
    8. Optional a = Optional.ofNullable(value1);
    9. // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
    10. Optional b = Optional.of(value2);
    11. System.out.println(java8Tester.sum(a,b));
    12. }
    13. public Integer sum(Optional a, Optional b){
    14. // Optional.isPresent - 判断值是否存在
    15. System.out.println("第一个参数值存在: " + a.isPresent());
    16. System.out.println("第二个参数值存在: " + b.isPresent());
    17. // Optional.orElse - 如果值存在,返回它,否则返回默认值
    18. Integer value1 = a.orElse(new Integer(0));
    19. //Optional.get - 获取值,值需要存在
    20. Integer value2 = b.get();
    21. return value1 + value2;
    22. }
    23. }

    执行以上脚本,输出结果为:

    $ javac Java8Tester.java 
    $ java Java8Tester 
    第一个参数值存在: false 
    第二个参数值存在: 
    true 10
    

    工作中经常会遇到,查询返回空,如果没有判空处理,一不小心就会空指针异常。

    从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException

    String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();

    在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:

    1. if(user !=null){
    2. Address address = user.getAddress();
    3. if (address != null) {
    4. Country country = address.getCountry();
    5. if (country != null) {
    6. String isocode = country.getIsocode();
    7. if (isocode != null) {
    8. isocode = isocode.toUpperCase();
    9. }
    10. }
    11. }
    12. }

    你看到了,这很容易就变得冗长,难以维护

    加上 if 判断处理也可以,但是会导致代码变得异常冗余,Java8有更优雅的处理方式

    1. public static void main(String[] args) {
    2.         List list = null;
    3.         List newList = Optional.ofNullable(list).orElse(Lists.newArrayList());
    4.         newList.forEach(x -> System.out.println(x));
    5.     }

    先解释代码含义:如果list集合不为空,将list集合赋值给newList;如果list集合为空创建一个空对象集合赋值给newList,保证list集合永远不为空,也就避免了空指针异常。(为了更好的理解,分开写了,比较庸俗,实际工作中都是一行搞定,哈哈哈)

    再看看源码:底层是怎么处理的,怎么就避免了空指针呢?

    1. //静态变量 empty
    2. private static final Optional EMPTY = new Optional<>();
    3.  
    4. //如果对象为空,执行empty()方法;不为空,执行of(value)方法
    5. public static Optional ofNullable(T value) {
    6.         return value == null ? empty() : of(value);
    7.     }
    8.  
    9. public static Optional empty() {
    10.         @SuppressWarnings("unchecked")
    11.         Optional t = (Optional) EMPTY;
    12.         return t;
    13.     }
    14.  
    15. public static Optional of(T value) {
    16.         return new Optional<>(value);
    17.     }

    1、首先执行ofNullable()方法,如果T对象为空,执行empty()方法;不为空,执行of(value)方法

    2、empty()方法,初始化一个空对象Optional(空对象和null不是一回事)

    3、of(value)方法,将泛型对象T用于Optional构造方法的参数上,返回一个有值的对象

    4、经过上面两步,从而保证了Optional不为null,避免了空指针

    JAVA 8/9 -- 理解、学习与使用 Java 中的 Optional (主要解决空指针NPE问题)_jiwei_style的博客-CSDN博客

  • 相关阅读:
    树莓派之快速上手-变身个人Linux电脑
    vue移动端H5调起手机发送短信(兼容ios和android)
    MindSpore:【resnet_thor模型】尝试运行resnet_thor时报Could not convert to
    【吴恩达机器学习-笔记整理】推荐算法,协同过滤,均值规范化
    Unity 3D 2022.1 AND UnityHub 3.2 Patch
    规范你的Typescript注释,一步一步教你生成API文档
    通过Linux deploy搭建Android服务器(包括git)
    【每日随笔】毕业论文答辩 ③ ( 线上答辩注意点 | 答辩 PPT 准备 | 答辩通过的因素 )
    二叉树的具体原理及实现
    Windows上使用QEMU创建aarch64(ARM64)虚拟机
  • 原文地址:https://blog.csdn.net/MinggeQingchun/article/details/130796263