Java8新特性之Optional
空指针异常一直是困扰Java程序员的问题,也是我们必须要考虑的。当业务代码中充满了if else判断null 的时候程序变得不再优雅,在Java8中提供了Optional类为我们解决NullPointerException。
我们先来看看这段代码有什么问题?
|
1
2
3
4
5
6
7
8
9
|
class User { String name; public String getName() { return name; }}public static String getUserName(User user){ return user.getName();} |
这段代码看起来很正常,每个User都会有一个名字。所以调用getUserName方法会发生什么呢? 实际这是不健壮的程序代码,当User对象为null的时候会抛出一个空指针异常。
我们普遍的做法是通过判断user != null然后获取名称
|
1
2
3
4
5
6
|
public static String getUserName(User user){ if(user != null){ return user.getName(); } return null;} |
但是如果对象嵌套的层次比较深的时候这样的判断我们需要编写多少次呢?难以想象
处理空指针
使用Optional优化代码
|
1
2
3
4
|
public static String getUserNameByOptional(User user) { Optional<String> userName = Optional.ofNullable(user).map(User::getName); return userName.orElse(null);} |
当user为null的时候我们设置UserName的值为null,否则返回getName的返回值,但此时不会抛出空指针。
在之前的代码片段中是我们最熟悉的命令式编程思维,写下的代码可以描述程序的执行逻辑,得到什么样的结果。 后面的这种方式是函数式思维方式,在函数式的思维方式里,结果比过程更重要,不需要关注执行的细节。程序的具体执行由编译器来决定。 这种情况下提高程序的性能是一个不容易的事情。
我们再次了解下Optional中的一些使用方法
Optional方法
创建 Optional 对象
你可以通过静态工厂方法Optional.empty,创建一个空的Optional对象:
|
1
|
Optional<User> emptyUser = Optional.empty(); |
创建一个非空值的Optional
|
1
|
Optional<User> userOptional = Optional.of(user); |
如果user是一个null,这段代码会立即抛出一个NullPointerException,而不是等到你试图访问user的属性值时才返回一个错误。
可接受null的Optional
|
1
|
Optional<User> ofNullOptional = Optional.ofNullable(user); |
使用静态工厂方法Optional.ofNullable,你可以创建一个允许null值的Optional对象。
如果user是null,那么得到的Optional对象就是个空对象,但不会让你导致空指针。
使用map从Optional对象中提取和转换值
|
1
2
|
Optional<User> ofNullOptional = Optional.ofNullable(user);Optional<String> userName = ofNullOptional.map(User::getName); |
这种操作就像我们之前在操作Stream是一样的,获取的只是User中的一个属性。
默认行为及解引用Optional对象
我们决定采用orElse方法读取这个变量的值,使用这种方式你还可以定义一个默认值, 遭遇空的Optional变量时,默认值会作为该方法的调用返回值。 Optional类提供了多种方法读取 Optional实例中的变量值。
- get()是这些方法中最简单但又最不安全的方法。如果变量存在,它直接返回封装的变量 值,否则就抛出一个NoSuchElementException异常。所以,除非你非常确定Optional 变量一定包含值,否则使用这个方法是个相当糟糕的主意。此外,这种方式即便相对于 嵌套式的null检查,也并未体现出多大的改进。
- orElse(T other)是我们在代码清单10-5中使用的方法,正如之前提到的,它允许你在 Optional对象不包含值时提供一个默认值。
- orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版,Supplier 方法只有在Optional对象不含值时才执行调用。如果创建默认值是件耗时费力的工作, 你应该考虑采用这种方式(借此提升程序的性能),或者你需要非常确定某个方法仅在 Optional为空时才进行调用,也可以考虑该方式(这种情况有严格的限制条件)。
- orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常类似, 它们遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow你可以定制希 望抛出的异常类型。
- ifPresent(Consumer<? super T>)让你能在变量值存在时执行一个作为参数传入的 方法,否则就不进行任何操作。
当前除了这些Optional类也具备一些和Stream类似的API,我们先看看Optional类方法:

用Optional封装可能为null的值
目前我们写的大部分Java代码都会使用返回NULL的方式来表示不存在值,比如Map中通过Key获取值, 当不存在该值会返回一个null。 但是,正如我们之前介绍的,大多数情况下,你可能希望这些方法能返回一个Optional对象。 你无法修改这些方法的签名,但是你很容易用Optional对这些方法的返回值进行封装。
我们接着用Map做例子,假设你有一个Map<String, Object>类型的map,访问由key的值时, 如果map中没有与key关联的值,该次调用就会返回一个null。
|
1
|
Object value = map.get("key"); |
使用Optional封装map的返回值,你可以对这段代码进行优化。要达到这个目的有两种方式: 你可以使用笨拙的if-then-else判断语句,毫无疑问这种方式会增加代码的复杂度; 或者你可以采用Optional.ofNullable方法
|
1
|
Optional<Object> value = Optional.ofNullable(map.get("key")); |
每次你希望安全地对潜在为null的对象进行转换,将其替换为Optional对象时,都可以考虑使用这种方法。
今天七夕,祝天下有情人终成眷属!
Java8新特性之Optional的更多相关文章
- 乐字节-Java8新特性之Optional
上一篇小乐带大家了解了Java新特性之Stream,接下来将会继续述说Java新特性之Optional Optional<T>类(java.util.Optional)是一个容器类,代表一 ...
- 【Java8新特性】Optional类在处理空值判断场景的应用 回避空指针异常 编写健壮的应用程序
一.序言 空值异常是应用运行时常见的异常,传统方式为了编写健壮的应用,常常使用多层嵌套逻辑判断回避空指针异常.Java8新特性之Optional为此类问题提供了优雅的解决方式. 广大程序员朋友对空值异 ...
- java8新特性之Optional类
NullPointException可以说是所有java程序员都遇到过的一个异常,虽然java从设计之初就力图让程序员脱离指针的苦海,但是指针确实是实际存在的,而java设计者也只能是让指针在java ...
- 【Java8新特性】- Optional应用
Java8新特性 - Optional应用 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...
- java8新特性六-Optional 类
Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Optional 是个容器:它可以保存类型T的值,或者仅仅保 ...
- Java8新特性之Optional,如何优雅地处理空指针
是什么 从 Java 8 引入的一个很有趣的特性是 Optional 类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException)-- 每个 Java ...
- 【Java8新特性】Optional 类
概述 Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Optional 是个容器:它可以保存类型T的值,或者 ...
- 乐字节-Java8新特性之Date API
上一篇文章,小乐给大家带来了Java8新特性之Optional,接下来本文将会给大家介绍Java8新特性之Date API 前言: Java 8通过发布新的Date-Time API来进一步加强对日期 ...
- 乐字节-Java8新特性-接口默认方法之Stream流(下)
接上一篇:<Java8新特性之stream>,下面继续接着讲Stream 5.流的中间操作 常见的流的中间操作,归为以下三大类:筛选和切片流操作.元素映射操作.元素排序操作: 操作 描述 ...
随机推荐
- jQuery——this
js注册事件this代表的dom对象 jQuery注册事件this代表的也是dom对象,所以需要$(this)转成jQuery对象
- [Windows Server 2012] 杰奇CMS安全设置
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com ★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频. ★ 本节我们将带领大家:JIEQI ...
- 06--ubuntu的sqlite安装
知道学习嵌入式技术,数据库是必须懂的,看的书上嵌入式的教程都在用,看来我是非学不可了,下面就简单的记录一下我在Ubuntu 12.04系统上安装 SQLite 的过程以及使用. 相关阅读: SQLit ...
- ats 与 https
一些证书相关的描述: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKe ...
- 如何创建一个项目,让gitlab自动触发jenkins进行构建
前进是:你已经配置好jenkins+gitlab自动化布置了,这里只是常规构建新的项目时,需要做的配置,记录下来,以免忘了又着急 参考这篇博客: https://www.jianshu.com/p/e ...
- 【Android】进程间通信IPC——Binder
Binder是Android中的跨进程通信方式,bindService的时候,服务端返回Binder对象,通过该对象客户端可以从服务端获取数据.在进程间通信IPC——AIDL中创建了ICustomAi ...
- vivado2018.3 与 modelsim联合仿真
我用的是目前最新版本的软件,vivado2018.3与modelsim10.6d.废话不多说,直接上操作 1.modelsim编译vivado库 1)双击启动vivado软件,如下图操作 2)Simu ...
- 洛谷——P2814 家谱
P2814 家谱 题目背景 现代的人对于本家族血统越来越感兴趣. 题目描述 给出充足的父子关系,请你编写程序找到某个人的最早的祖先. 输入输出格式 输入格式: 输入由多行组成,首先是一系列有关父子关系 ...
- exgcd扩展欧几里得求解的个数
知识储备 扩展欧几里得定理 欧几里得定理 (未掌握的话请移步[扩展欧几里得]) 正题 设存在ax+by=gcd(a,b),求x,y.我们已经知道了用扩欧求解的方法是递归,终止条件是x==1,y==0: ...
- VsCode 格式化插件配置
Beautify 1.在工作目录下建立.jsbeautifyrc文件: { "brace_style": "none,preserve-inline", &qu ...