一、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() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。

4和5示例:

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);}

控制台输出:

入选:钱七
入选:吴九

Java 8特性之Optional详解相关推荐

  1. 【java8新特性】——Optional详解(三)

    一.简介 Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引入的一个同名Optional类,使用Optional类可以避免显式的null ...

  2. java lambda表达式详解_Java8新特性Lambda表达式详解

    课程目标: 通过本课程的学习,详细掌握Java8新特性之Lambda表达式: 适用人群:有Java基础的开发人员: 课程概述:从Java 8出现以来lambda是最重要的特性之一,它可以让我们用简洁流 ...

  3. 【Java 8 新特性】Java 8 Util API: StringJoiner 详解 | 拼接字符串添加分隔符、前缀和后缀

    Java 8 Util API: StringJoiner 详解 StringJoiner(CharSequence d) StringJoiner.add(CharSequence element) ...

  4. Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3

    Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3 总览 问题 详解 String.intern()的作用 link LeetCode的Two Sum题 ...

  5. Java 1.8 函数式编程详解

    Java 1.8 函数式编程详解 文章目录 Java 1.8 函数式编程详解 一. 概述 1.1 java 8 新特性: 二. 函数式接口 2.1 函数式接口概述 2.2 Lambda表达式概述 2. ...

  6. Java多线程之volatile详解

    Java多线程之volatile详解 目录: 什么是volatile? JMM内存模型之可见性 volatile三大特性之一:保证可见性 volatile三大特性之二:不保证原子性 volatile三 ...

  7. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  8. Java stream流式计算详解

    Java stream流式计算详解 1. Stream概述 1.1 Stream简介 1.2 Stream分类 2. Stream操作 2.1 Stream创建 2.2 Stream无状态操作 2.3 ...

  9. Java开发常见面试题详解(JVM)_2

    Java开发常见面试题详解(JVM)_2 JVM 问题 详解 JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots link 你说你做过JVM调优和参数配置,请问如何盘点查看JVM系统默认 ...

最新文章

  1. 通过网络安装VMware ESX Server 5
  2. pandas将dataframe中的年、月、日数据列合并成完整日期字符串、并使用to_datetime将字符串格式转化为日期格式
  3. 摄像头图像桶形畸变校正测试
  4. 【Linux 内核】调度器 ④ ( sched_class 调度类结构体分析 | yield_task 函数 | heck_preempt_curr 函数 | task_struct 函数 )
  5. .net中如何生成不重复的随机数
  6. 由于昨天没发博客,在此向广大粉丝们道歉。 今天发的是一个数据库的代码
  7. Avalonia跨平台入门第一篇
  8. pandas 0.22导入错误
  9. JS-函数(匿名-自调用-回调)-递归
  10. Spark SQL运行原理和架构
  11. request 获取url
  12. matlab中subplot()函数的作用
  13. telegtram的通信协议MTproto2.0学习3 之 (telethon代码分析与TL的实现1)
  14. Stata+R: 一文读懂中介效应分析
  15. 海康威视摄像头使用:iVMS-4200 VS客户端
  16. Selenium+Appium底层原理
  17. 如何下载jQuery
  18. Tableau可视化项目
  19. 大量discuz电脑模板企业模板手机模板免费下载,百度云下载地址
  20. allegro中design size无法修改

热门文章

  1. 婚纱摄影服务预约小程序项目开发
  2. 内存泄漏检测工具valgrind神器
  3. 接口联调务必按照文档走
  4. 科普文章|一文读懂Moonbeam收集人及质押机制
  5. 软件公司美工的地位!
  6. Hive面试-情景题总结【包含:建表脚本、数据导入脚本、模拟数据】
  7. 大数据篇:如何区分流处理和批处理
  8. 计算机学硕330调剂,武汉大学2017年计算机学院硕士生接收调剂复试的说明_武汉大学考研网...
  9. Win10快速启动、待机(睡眠)、休眠、混合睡眠是什么?
  10. 温岭天气预报软件测试,温岭天气预报15天