Java 8 新特性 Optional 类学习,理解并应用。NullPointerException空值检测

简介: JDK1.8开始引入的特性,Optional 类主要解决空指针异常(NullPointerException)问题。Optional类是一个可能包含或不包含非空值(可以为null)的容器对象。 如果一个值存在,调用 isPresent()方法将返回true、get()方法将返回该对象。 Optional类提供判断空值的方法,使用其中方法可以不用再显式地进行空值检测。

🍀Optional 类

JDK1.8开始引入的特性,Optional 类主要解决空指针异常(NullPointerException)问题。

Optional类是一个可能包含或不包含非空值(可以为null)的容器对象。 如果一个值存在,调用 isPresent()方法将返回true、get()方法将返回该对象。

Optional类提供判断空值的方法,使用其中方法可以不用再显式地进行空值检测。

举例:
User类的结构
在这里插入图片描述

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

在避免出现空指针的情况下,我们常常需要将代码改造成这样:

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

在避免了空指针异常的情况下,代码变得冗长,且增加了之后的运维难度。

而利用Optional类,可以将这一判断过程变得赏心悦目。

重构下类,将getter方法修改成返回Optional引用

public class Address {
    private Country country;

    public Optional<Country> getCountry() {
        return Optional.ofNullable(country);
    }
    // ...
}

public class User {
    private Address address;
    
    public Optional<Address> getAddress() {
        return Optional.ofNullable(address);
    }
    // ...
@Test
public void whenChaining_thenOk() {
    User user = new User("berbai@88.com", "ber");

    String result = Optional.ofNullable(user)
      .flatMap(u -> u.getAddress())
      .flatMap(a -> a.getCountry())
      .map(c -> c.getIsocode())
      .orElse("default");

    assertEquals(result, "default");
}

通过方法引用可进一步简化代码

     String result2 = Optional.ofNullable(user)
             .flatMap(User::getAddress)
             .flatMap(Address::getCountry)
             .map(Country::getIsocode)
             .orElse("default");

🍀方法介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

🍀Optional应用

创建 Optional 实例

// 创建一个空的Optional对象,此时调用emptyOpt 存在NoSuchElementException
Optional<User> emptyOpt = Optional.empty();
// 创建包含值的 Optional。注意:user必需不为空,否则NullPointerException
Optional<User> opt = Optional.of(user);
// 创建可能包含值或可能为空的 Optional。user可以为空
Optional<User> opt = Optional.ofNullable(user);

访问 Optional 对象的值

String name = "Ber";
Optional<String> opt = Optional.ofNullable(name);
// get() 如果 opt中有一个值,返回值,否则抛出 NoSuchElementException 。 
System.out.println(opt.get());  // 输出Ber,opt为空则NoSuchElementException
// 所以先判断opt是否空
opt.isPresent(); // 返回 true如果存在值,否则为 false 。
opt.ifPresent( u -> System.out.println(u)); // 只有 name 不为 null 的时候才会执行输出。

为空时返回默认值

  1. orElse()
String nameNull = null;
String name = "Ber";
// nameNull 为空,默认值则为name。
System.out.println(Optional.ofNullable(nameNull).orElse(name)); // 输出Ber

String name2 = "默认值";
// 如果对象初始值不为空,则默认值会被忽略
System.out.println(Optional.ofNullable(name).orElse(name2)); // 输出Ber,而不是默认值
  1. orElseGet()
// 在有值的时候返回值,如果为空,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果
System.out.println(Optional.ofNullable(nameNull).orElseGet( () -> name)); // 输出Ber
  1. orElse() 和 orElseGet()的区别

在Optional对象为不为空时,两个方法都返回相应的非空值,但orElse()方法任创建了默认值对象,而orElseGet()方法不再创建。

为空返回异常

String nameNull = null;
// 这里设定为空返回IllegalArgumentException‎,返回异常可自行定义
Optional.ofNullable(nameNull).orElseThrow( () -> new ‎IllegalArgumentException‎());

Optional对象转换值

  1. map()

如果存在一个值,则应用提供的映射函数,如果结果不为空,则返回一个 Optional结果的 Optional 。

User user = new User("berbai@88.com", "ber");
String email = Optional.ofNullable(user).map(u -> u.getEmail()).orElse("default@gmail.com");
  1. flatMap()

如果一个值存在,应用提供的 Optional映射函数给它,返回该结果,否则返回一个空的 Optional 。

// 在User类增加返回 Optional 方法
public class User {    
    private String sex;

    public Optional<String> getSex() {
        return Optional.ofNullable(sex);
    }
    //...
}

User user = new User("berbai@88.com", "ber");
user.setSex("男")
String position = Optional.ofNullable(user).flatMap(u -> u.getSex()).orElse("女");

Optional过滤值

  1. filter()

如果一个值存在,并且该值给定的谓词相匹配时,返回一个 Optional描述的值,否则返回一个空的 Optional 。

User user = new User("berbai@88.com", "ber");
// email必须包含‘@’
Optional<User> result = Optional.ofNullable(user).filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
目录
相关文章
|
6天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
15天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
8天前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
20 4
|
8天前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
20 3
|
10天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
16天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
30 3
|
16天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
33 2
|
17天前
|
缓存 Java 数据库连接
Hibernate:Java持久层框架的高效应用
通过上述步骤,可以在Java项目中高效应用Hibernate框架,实现对关系数据库的透明持久化管理。Hibernate提供的强大功能和灵活配置,使得开发者能够专注于业务逻辑的实现,而不必过多关注底层数据库操作。
12 1
|
18天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
3月前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
58 7