空指针异常一直是困扰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. python 之 sqlite3

    # -*- coding: utf-8 -*- ''' 创建数据库日志,三列为时间 身份证号和备注名''' import os import sys import sqlite3 import dat ...

  2. Ajax——异步基础知识(二)

    XML数据格式 首行必须是版本号和格式等信息 <?xml version="1.0" encoding="utf-8" ?> 最外层需要一个根节点进 ...

  3. 基于saltstack svn的一个发布系统

      1.登录页 2.分组管理页 3.添加项目页 4.项目列表和项目编辑页 5.项目发布回滚页

  4. (转)Hibernate的配置详解

    http://blog.csdn.net/yerenyuan_pku/article/details/65041077 在<Hibernate快速入门>一文中,我有讲到Hibernate的 ...

  5. HDU_1026_Ignatius and the Princess I_BFS(保存路径)

    Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  6. JVM 内存设置大小(Xms Xmx PermSize MaxPermSize 区别)

    Eclipse崩溃,错误提示:MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) sp ...

  7. python socket 接口

    一.简介 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求.socket起 ...

  8. react typescript 子组件调用父组件

    //父组件 import * as React from 'react'import { Input } from 'antd'const Search = Input.Searchimport &q ...

  9. iptables简单了解

    简介 Iptables是unix/linux自带的一款优秀且开源的基于包过滤的防火墙工具. 怎么用 可以用来做主机防火墙. 可以做局域网共享上网. 可以做ip及端口映射. Iptables工作流程 i ...

  10. HTML学习笔记之标签基础

    目录 1.基本标签 2.链接 3.图像 4.表格 5.列表 6.块与布局 1.基本标签 (1)标题与段落 标签 <h1> ~ <h6> 分别用于定义一至六级标题,标签 < ...