空指针异常一直是困扰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的更多相关文章

  1. 乐字节-Java8新特性之Optional

    上一篇小乐带大家了解了Java新特性之Stream,接下来将会继续述说Java新特性之Optional Optional<T>类(java.util.Optional)是一个容器类,代表一 ...

  2. 【Java8新特性】Optional类在处理空值判断场景的应用 回避空指针异常 编写健壮的应用程序

    一.序言 空值异常是应用运行时常见的异常,传统方式为了编写健壮的应用,常常使用多层嵌套逻辑判断回避空指针异常.Java8新特性之Optional为此类问题提供了优雅的解决方式. 广大程序员朋友对空值异 ...

  3. java8新特性之Optional类

    NullPointException可以说是所有java程序员都遇到过的一个异常,虽然java从设计之初就力图让程序员脱离指针的苦海,但是指针确实是实际存在的,而java设计者也只能是让指针在java ...

  4. 【Java8新特性】- Optional应用

    Java8新特性 - Optional应用 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...

  5. java8新特性六-Optional 类

    Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Optional 是个容器:它可以保存类型T的值,或者仅仅保 ...

  6. Java8新特性之Optional,如何优雅地处理空指针

    是什么 ​ 从 Java 8 引入的一个很有趣的特性是 Optional 类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException)-- 每个 Java ...

  7. 【Java8新特性】Optional 类

    概述 Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Optional 是个容器:它可以保存类型T的值,或者 ...

  8. 乐字节-Java8新特性之Date API

    上一篇文章,小乐给大家带来了Java8新特性之Optional,接下来本文将会给大家介绍Java8新特性之Date API 前言: Java 8通过发布新的Date-Time API来进一步加强对日期 ...

  9. 乐字节-Java8新特性-接口默认方法之Stream流(下)

    接上一篇:<Java8新特性之stream>,下面继续接着讲Stream 5.流的中间操作 常见的流的中间操作,归为以下三大类:筛选和切片流操作.元素映射操作.元素排序操作: 操作 描述 ...

随机推荐

  1. Json——Json与JS的区别

    JSON是JS的字面量的特殊表现形式,它使用文本表示 JS 对象信息,本质是字符串 var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包 ...

  2. [Windows Server 2008] 服务器安全加固

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:服务器安全加固 ...

  3. (转) Arcgis for Javascript实现两个地图的联动

    http://blog.csdn.net/gisshixisheng/article/details/40127895 今天在看天地图的时候,有一个多时相的地图显示功能,感觉很好玩,作为技术控的我晚上 ...

  4. ICMP,ARP协议

    ICMP ICMP是(Internet Control Message Protocol)Internet控制报文协议.它是TCP/IP协议族的一个子协议,用于在IP主机.路由器之间传递控制消息.控制 ...

  5. 解决Mysql Workbench的Error Code: 1175错误

    错误: Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE ...

  6. typeof和instanceof的区别

    typeof和instanceof的区别: typeof typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型.它返回值是一个字符串,该字符串说明运算数的类型.typeof 一般只能 ...

  7. ceph对接openstack环境

    环境准备: 保证openstack节点的hosts文件里有ceph集群的各个主机名,也要保证ceph集群节点有openstack节点的各个主机名 一.使用rbd方式提供存储如下数据: (1)image ...

  8. Luogu P1629 邮递员送信

    P1629 邮递员送信 题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要 ...

  9. PHP常用系统设置整理

    1.设置时间脚本执行时间 set_time_limit(0); 2.设置最大执行内存 ini_set('memory_limit','1024M');//设置内存 memory_get_usage() ...

  10. JQ + PHP + TrackMore物流信息跟踪

    在使用之前,您需要先去trackmore官方网站申请API_KEY,传送门:TrackMore html <script type="text/javascript" src ...