终结 Java 空指针异常!优雅方案解析与案例演示

目录

⭐️引言

⭐️产生原因

⭐️优雅解析

⭐️代码示例

        优雅解决方案一:条件判断

        优雅解决方案二:断言与异常处理

        优雅解决方案三:使用 Objects 类的 requireNonNull 方法

        优雅解决方案三:Optional 类的妙用

⭐总结


⭐️引言

        NullPointerException(空指针异常)是 Java 开发者经常遇到的问题,它通常由于访问或操作一个空对象引起。本文将详细介绍如何优雅地识别、解析和处理这个问题。

⭐️产生原因

详解导致 NullPointerException 的主要原因:

  • 对空对象的属性或方法调用
  • 未初始化的变量使用
  • 数组未初始化访问
  • 返回值为 null 的方法调用 

⭐️优雅解析

为了更好地解析和定位 NullPointerException,我们可以采取以下步骤:

  • 异常栈轨迹分析
  • 可能为空的变量逐一排查
  • 使用断言和条件检查
  • 利用 Optional 类来处理可能为空的值

⭐️代码示例

        优雅解决方案一:条件判断

        使用条件判断,避免对可能为 null 的对象进行操作,从而消灭潜在的空指针异常。

import java.util.Optional;

public class NPEElimination {
    public static void main(String[] args) {
        // 解决方案一:条件判断
        String name = null;
        if (name != null) {
            System.out.println("Hello, " + name + "!");
        }
    }

}

        这种写法是比较丑陋的,为了避免上述丑陋的写法,让丑陋的设计变得优雅。JAVA8提供了Optional类来优化这种写法,接下来的正文部分进行详细说明

      

       优雅解决方案二:断言与异常处理

        合理运用断言和异常处理机制,增强代码健壮性,避免空指针问题在代码中蔓延。

import java.util.Optional;

public class NPEElimination {
    public static void main(String[] args) {

        // 解决方案二:断言与异常处理
        String city = getCity();
        assert city != null : "City should not be null";
        System.out.println("City: " + city);

    }

    static String getCity() {
        return "New York";
    }

    static String getUsername() {
        return null;
    }
}

        优雅解决方案三:使用 Objects 类的 requireNonNull 方法

        利用 Java 7 引入的 Objects 类提供的 requireNonNull 方法,实现更简洁的空指针检查。

import java.util.Objects;

public class RequireNonNullExample {
    public static void main(String[] args) {
        String city = null;

        // 方案二:使用 requireNonNull 方法
        city = Objects.requireNonNull(city, "City should not be null");
        System.out.println("City: " + city);
    }
}

        优雅解决方案三:Optional 类的妙用

        解析 Optional 源码: Optional 类是 Java 8 引入的一个用于处理可能为 null 的值的容器。它提供了丰富的 API,如 of、ofNullable、isPresent、ifPresent、orElse 等方法,能够帮助开发者优雅地处理可能为空的值,避免繁琐的空指针检查。

通过深入阅读 Optional 类的源码,你可以掌握以下核心概念:

        1.内部属性:Optional 内部维护一个 value 属性,可以是实际的非空值,也可以是 null。

        在 Optional 类中,value 属性是用于保存实际的非空值或者 null 的。该属性的类型为泛型 T,表示可以保存任意类型的值。

        源码解析: value 属性在 Optional 类中是一个 final 修饰的字段,用于保存实际的值。当 Optional 对象包含一个非空值时,value 属性将引用该值;当 Optional 对象为空时,value 属性为 null

以下是 Optional 类中的部分源码,展示了 value 属性的定义和初始化:

public final class Optional<T> {

    // 实际的值,可以是非空值或者 null
    private final T value;

    // 构造方法,用于创建包含非空值的 Optional
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    // 构造空的 Optional
    private Optional() {
        this.value = null;
    }

    // ...
}

        使用案例: 以下是一个示例,演示如何使用 Optionalvalue 属性来存储实际的非空值或者 null

import java.util.Optional;

public class ValueAttributeExample {
    public static void main(String[] args) {
        String name = "John";

        // 创建包含非空值的 Optional
        Optional<String> optionalName = Optional.of(name);
        if (optionalName.isPresent()) {
            System.out.println("Name: " + optionalName.get()); // 输出:Name: John
        }

        // 创建空的 Optional
        Optional<String> emptyOptional = Optional.empty();
        if (!emptyOptional.isPresent()) {
            System.out.println("Empty Optional"); // 输出:Empty Optional
        }
    }
}
  1. of 和 ofNullable 方法:用于创建 Optional 对象,其中 of 方法要求传入非空值,而 ofNullable 方法可以接受可能为空的值。

        Optional 类中的 ofofNullable 方法是用于创建 Optional 对象的两种方式,它们分别对应于传入非空值和可能为空的值。让我们深入了解它们的源码和使用案例。

        源码解析: ofofNullable 方法在 Optional 类中是静态方法。它们用于创建包含指定值的 Optional 对象,其中 of 方法要求传入非空值,而 ofNullable 方法可以接受可能为空的值。

以下是 Optional 类中的部分源码,展示了 ofofNullable 方法的定义和实现:

public final class Optional<T> {

    // 静态方法,创建包含指定非空值的 Optional
    public static<T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    // 静态方法,创建包含指定值(可能为空)的 Optional
    public static<T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    // ...
}

        使用案例: 以下是一个示例,演示如何使用 ofofNullable 方法来创建不同类型的 Optional 对象:

import java.util.Optional;

public class OfAndOfNullableExample {
    public static void main(String[] args) {
        String name = "John";

        // 使用 of 创建包含非空值的 Optional
        Optional<String> optionalName = Optional.of(name);
        if (optionalName.isPresent()) {
            System.out.println("Name: " + optionalName.get()); // 输出:Name: John
        }

        // 使用 ofNullable 创建包含可能为空的 Optional
        String nullValue = null;
        Optional<String> nullableOptional = Optional.ofNullable(nullValue);
        if (!nullableOptional.isPresent()) {
            System.out.println("Value is null"); // 输出:Value is null
        }
    }
}
  1. isPresent 方法:判断 Optional 对象是否包含非空值。
  2. ifPresent 方法:在包含非空值的情况下,执行传入的操作。
public final class Optional<T> {
    //省略....
    public boolean isPresent() {
        return value != null;
    }
    //省略...
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
}
 Optional.ofNullable(user)
    .ifPresent(u->{
        dosomething(u);
});
  1. orElse 方法:在 Optional 为空时,返回一个默认值。

   orElse 方法是 Optional 类中常用的一个方法,用于在 Optional 为空时返回一个默认值。这可以有效地处理可能为空的情况,避免了空指针异常。

        源码解析: orElse 方法的源码很简单,它接受一个参数作为默认值,如果 Optional 对象为空,则返回传入的默认值。

以下是 Optional 类中的部分源码,展示了 orElse 方法的定义和实现:

public final class Optional<T> {

    // 返回值或默认值
    public T orElse(T other) {
        return value != null ? value : other;
    }

    // ...
}

        使用案例: 以下是一个示例,演示如何使用 orElse 方法来处理可能为空的 Optional,并提供一个默认值:

  1. filter 和 map 方法:用于对 Optional 内的值进行过滤和映射。
public final class Optional<T> {
    //省略....
   Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
}

使用案例如下:

Optional<User> user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);
  1. flatMap 方法:用于处理嵌套的 Optional,降低 Optional 嵌套层次。
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

使用案例如下:

 // 使用 flatMap 处理嵌套的 Optional
        String result = optionalBook.flatMap(Book::getAuthorName)
                                   .orElse("Unknown Author");
  1. 空 Optional:Optional.empty() 表示空的 Optional。

        源码解析: flatMap 方法的源码定义在 java.util.Optional 类中,其签名如下:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

flatMap 方法接受一个函数 mapper,该函数将原始 Optional 的值映射为另一个 Optional,然后将嵌套的 Optional 展平为一个单层的 Optional。如果原始 Optional 为空,或者 mapper 映射的 Optional 为空,那么 flatMap 返回一个空的 Optional

        使用案例: 假设我们有一个场景,要从一本书的 Optional 中获取作者的名字,而作者的名字也被包装在一个 Optional 中。使用 flatMap 方法可以简洁地处理这种情况。

下面是一个示例代码,演示如何使用 flatMap 方法处理嵌套的 Optional

import java.util.Optional;

class Book {
    private String authorName;

    public Book(String authorName) {
        this.authorName = authorName;
    }

    public Optional<String> getAuthorName() {
        return Optional.ofNullable(authorName);
    }
}

public class FlatMapExample {
    public static void main(String[] args) {
        Book book = new Book("John Doe");
        Optional<Book> optionalBook = Optional.of(book);

        // 使用 flatMap 处理嵌套的 Optional
        String result = optionalBook.flatMap(Book::getAuthorName)
                                   .orElse("Unknown Author");

        System.out.println("Author: " + result);
    }
}

⭐总结

        通过本文的精彩演绎,你将彻底掌握解决 Java 空指针异常的多种优雅方法,在生产环境中我们可以通过Sonar 代码检测工具来检测代码问题,暴露出空指针所在位置,深入理解 Optional API 的精髓,助力你的代码更加健壮、可靠,从而成为更出色的 Java 开发者。

                                                            ⏳  名言警句:说会的,说对的
                                                            ✨ 原创不易,还希望各位大佬支持一下
                                                            👍 点赞,你的认可是我创作的动力!
                                                            ⭐️ 收藏,你的青睐是我努力的方向!
                                                            ✏️ 评论,你的意见是我进步的财富!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值