浅谈Java8的特性之Optional类

 更新时间:2023年08月14日 10:32:59   作者:Pluto372  
这篇文章主要介绍了浅谈Java8的特性之Optional类,Optional类是 Java 8 引入的一个很有趣的特性,Optional 类是一个可以为null的容器对象,它主要解决的问题是臭名昭著的空指针异常,需要的朋友可以参考下

一、Optional类 简介

Optional类是 Java 8 引入的一个很有趣的特性。它主要解决的问题是臭名昭著的空指针异常(NullPointerException)

  • Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
  • Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
  • Optional 类的引入很好的解决空指针异常。

Optional 是一个对象容器,具有以下两个特点:

  • 提示用户要注意该对象有可能为null
  • 简化if else代码

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

用户 -> 家庭住址  -> 城市  ->邮编
String postCode = user.getAddress().getCity().getPostCode();

在这个示例中,为了避免异常,就得在访问每一个值之前对其进行明确地检查:

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        City city= address.getCity();
        if (city != null) {
            String postCode = city.getPostCode();
            if (postCode != null) {
            	//对postCode进行操作
               test(postCode);
            }
        }
    }
}

这很容易就变得冗长,难以维护。 为了简化这个过程,我们就可以用 Optional 类。

二、Optional类的使用

1. 创建:

Optional类的实例创建有三种方式:

  • Optional.empty() :创建一个空的 Optional 实例。
  • Optional.of(T t) :创建一个 Optional 实例,当 t为null时抛出异常(NullPointerException)。
  • Optional.ofNullable(T t) :创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例。

2. 获取:

  • get():获取optional实例中的对象,当optional 容器为空时报错。

3. 判断:

  • isPresent():判断optional是否为空,如果空则返回false,否则返回true
  • ifPresent(Consumer c):如果optional不为空,则将optional中的对象传给Comsumer函数
public class OptionalDemo {
    public static void main(String[] args) {
        User user = new User("王也", "5");
        User userNull= null;
        Optional<User> optional = Optional.ofNullable(user);
        System.out.println(optional.isPresent());
        optional.ifPresent(u -> System.out.println("optional不为null  "+u));
    }
}

在这里插入图片描述

  • orElse(T other):如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值
   User user = new User("王也", "5");
   User userNull= null;
   //orElse的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值:
   User user1 = Optional.ofNullable(userNull).orElse(user);
   System.out.println(user1);
   //控制台输出:User(name=王也, age=5)
  • orElseGet(Supplier other):如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other
  User user1 = Optional.ofNullable(userNull).orElseGet(()->user );
  //结果同上
  • orElseThrow(Supplier exception):如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常
//这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException。
 User result = Optional.ofNullable(userNull)
      .orElseThrow( () -> new IllegalArgumentException());

orElse() 和 orElseGet() 的不同之处

乍一看,这两种方法似乎起着同样的作用。然而事实并非如此。我们创建一些示例来突出二者行为上的异同。

(1)当对象为空时:

public class OptionalDemo {
    public static void main(String[] args) {
        User userNull = null;
        System.out.println("使用orElse():");
        User result = Optional.ofNullable(userNull).orElse(createNewUser());
        System.out.println("使用orElseGet():");
        User result2 = Optional.ofNullable(userNull).orElseGet(() -> createNewUser());
    }
    private static User createNewUser() {
        System.out.println("Creating New User");
        return new User("新的user对象", "1234");
    }
}

上面的代码中,两种方法都调用了 createNewUser() 方法,这个方法会记录一个消息并返回 User 对象。

控制台输出:

使用orElse():
Creating New User
使用orElseGet():
Creating New User

由此可见,当对象为空而返回默认对象时,行为并无差异。

(2)当对象不为空时:

public class OptionalDemo {
    public static void main(String[] args) {
        User user = new User("王也", "5");
        System.out.println("使用orElse():");
        User result = Optional.ofNullable(user).orElse(createNewUser());
        System.out.println("使用orElseGet():");
        User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
    }
    private static User createNewUser() {
        System.out.println("Creating New User");
        return new User("新的user对象", "1234");
    }
}

控制台输出:

使用orElse():
Creating New User
使用orElseGet():

这个示例中,两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。

在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。

4. 过滤:

filter(Predicate p):filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。

5. 映射:

  • map(Function<T, U> mapper):如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中。
  • flatMap(Function<T,Optional > mapper):跟上面一样,在optional不为空的情况下,将对象t映射成另外一个optional

map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。这就使对返回值进行链试调用的操作成为可能 —— 这里的下一环就是 orElse()。

flatMap() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。

过滤和映射的示例

public class OptionalDemo {
    public static void main(String[] args) {
        List<Student> studentList = initData();
        for (Student student : studentList) {
            Optional<Student> studentOptional = Optional.of(student);
            Integer score = studentOptional.filter(s -> s.getAge() >= 18).map(Student::getScore).orElse(0);
            if (score > 80) {
                System.out.println("入选:" + student.getName());
            }
        }
    }
    private static List<Student> initData(){
        Student s1 = new Student("张三", 19, 80);
        Student s2 = new Student("李四", 19, 50);
        Student s3 = new Student("王五", 23, null);
        Student s4 = new Student("赵六", 16, 90);
        Student s5 = new Student("钱七", 18, 99);
        Student s6 = new Student("孙八", 20, 40);
        Student s7 = new Student("吴九", 21, 88);
        return Arrays.asList(s1, s2, s3, s4, s5, s6, s7);
    }
}

使用stream流的写法:

 public static void main(String[] args) {
        List<Student> studentList = initData();
        List<String> studentName = studentList.stream().filter(student -> student.getAge() >= 18)
                .filter(student -> student.getScore() != null && student.getScore() > 80)
                .map(student -> student.getName()).collect(Collectors.toList());
        System.out.println(studentName);
    }

控制台输出:

入选:钱七
入选:吴九

到此这篇关于浅谈Java8的特性之Optional类的文章就介绍到这了,更多相关Java的Optional类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用Java实现文件锁定功能

    利用Java实现文件锁定功能

    这篇文章主要为大家详细介绍了如何利用Java语言实现文件锁定功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-08-08
  • SpringBoot3和4的版本新特性及升级要点详解

    SpringBoot3和4的版本新特性及升级要点详解

    Spring Boot 4.0作为生态内的重大更新,基于Spring Framework 6.1+ 构建,带来了一系列颠覆性优化,这篇文章主要介绍了SpringBoot3和4的版本新特性及升级要点的相关资料,需要的朋友可以参考下
    2026-03-03
  • Java实体类常用注解的用法

    Java实体类常用注解的用法

    这篇文章主要介绍了Java实体类常用注解的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • 使用Java实现视频与音频转码

    使用Java实现视频与音频转码

    这篇文章主要为大家详细介绍了如何使用Java实现视频与音频转码,即把其他视频格式转换成HTML5能播放的视频格式和把其他音频格式转换为mp3,感兴趣的小伙伴可以了解下
    2025-07-07
  • 关于在使用Lombok时maven install找不到符号问题的解决办法

    关于在使用Lombok时maven install找不到符号问题的解决办法

    Maven环境下开发项目时,尤其是涉及Lombok或其他依赖时,IDE会在构建和编译过程中进行注解处理,这篇文章主要介绍了关于在使用Lombok时maven install找不到符号问题的解决办法,需要的朋友可以参考下
    2025-10-10
  • SpringCloud Hystrix 断路器的实现

    SpringCloud Hystrix 断路器的实现

    本文主要介绍了SpringCloud Hystrix 断路器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-03-03
  • Java面向对象编程中final关键字的使用方法详解

    Java面向对象编程中final关键字的使用方法详解

    这篇文章主要介绍了Java面向对象编程中final关键字的使用方法详解,包括对内部匿名类无法访问外面的非 final 的变量问题的解读,需要的朋友可以参考下
    2016-06-06
  • 一文弄懂Maven依赖范围

    一文弄懂Maven依赖范围

    本文详细介绍了Maven依赖范围的概念、应用及其在项目构建和管理中的重要性,依赖范围包括compile、provided、runtime、test和system等类型,每种范围定义了依赖在不同构建阶段的可用性和打包行为,感兴趣的可以了解一下
    2024-11-11
  • JSON,AJAX,Maven入门基础

    JSON,AJAX,Maven入门基础

    这篇文章主要介绍了JSON,AJAX和Maven基础,如何使用AJAX读取Json数组里面的数据,感兴趣的小伙伴们可以参考一下,希望能够帮助到你
    2021-07-07
  • 关于application.yml数据库配置方式

    关于application.yml数据库配置方式

    这篇文章主要介绍了关于application.yml数据库配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08

最新评论