Java8避免空指针异常Optional类的使用

最近都是一天写一篇算法题解,好久没有写过博客了,不知道写啥了而且快到期末考试了。。

今天介绍一个Java8的特性:Optional类,这个类我平时也不咋用,今天来研究一下。

Optional的介绍与创建

Optional可以看作一个对象的容器,内部可以有一个对象,也可以没有(为空)。

通过下面的API可以创建一个Optional对象:

// 将传入的参数包装为一个Optional容器,不允许是null,否则报NullPointerException
Optional<String> optional = Optional.of("123");

// 如果参数是null,返回一个空容器,否则返回一个包装着该对象的容器
Optional<String> optional = Optional.ofNullable("123");

获得了一个Optional对象之后,就有很多有意思的操作了:

Optional的操作方法

get

最简单的取出容器内的元素,就是get方法,注意如果容器为空,抛出NoSuchElementException异常

Optional<String> optional = Optional.ofNullable("123");
// 获取容器中的值,如果容器为空,抛出NoSuchElementException异常
System.out.println(optional.get());

isPresent

判断容器中是否有值(不为空),返回一个布尔值:

// 容器中是否有值(不为空)
System.out.println(optional.isPresent());

ifPresent

ifPresent就要配合同是Java8特性的函数式接口来使用了,如果容器中存在值,就调用传入的一个Consumer来消耗它,例如:

// 如果容器中存在值,则消费,不存在则不做任何事
optional.ifPresent(e-> System.out.println(e));

也可以使用方法引用来改写这行代码:

optional.ifPresent(System.out::println);

orElse

如果容器为空,直接调用get方法会报异常,那么可以使用orElse方法获取一个值,它类似于HashMap的getOrDefault,如果容器为空,则返回传入的参数对象。

// 如果容器为空,返回"123",否则返回容器中的对象
System.out.println(optional.orElse("123"));

orElseGet

orElseGet和orElse很像,只是若容器为空orElse返回的对象是传入的参数,而orElseGet是通过传入的一个Supplier获取返回的对象:

// 如果容器为空,返回"123",否则返回容器中的对象
System.out.println(optional.orElseGet(() -> "123"));

orElseThrow

orElseThrow要求提供一个异常的Supplier,如果容器为空,则抛出通过Supplier获取的异常。

// 如果容器为空,抛出RuntimeException异常
System.out.println(optional.orElseThrow(() -> new RuntimeException()));

filter

配合函数式接口来使用,传入一个Predicate用于过滤容器中的值,如果满足给定的条件,则保留容器中的值,否则返回一个空容器:

public void testFilter(){
    Optional<Integer> optional = Optional.of(3);
    optional.filter(e->e<0).ifPresent(System.out::println);
}

map

map这个方法很有用,也是配合函数式接口来使用,传入一个Function,用返回的元素替换容器中的元素,注意如果容器原来为空的,则替换后也为空,如果返回的元素是null,也会包装为一个空容器。

public void testFilter(){
    Optional<Integer> optional = Optional.of(3);
    optional.map(e->e+3).ifPresent(System.out::println);
}

比较实用的做法是,获取一个对象内部字段,可以通过这个方法,避免空指针异常

class User{
    public Integer age;
    public User(Integer age) {
        this.age = age;
    }
}

@Test
public void testMap(){
    User user = new User(3);
    Optional.ofNullable(user).map(e->e.age).ifPresent(System.out::println);
}

flatMap

flatMap和map很像,区别在于,flatMap不允许替换的元素是null,否则会报NullPointerException异常

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java8%e9%81%bf%e5%85%8d%e7%a9%ba%e6%8c%87%e9%92%88%e5%bc%82%e5%b8%b8optional%e7%b1%bb%e7%9a%84%e4%bd%bf%e7%94%a8/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年6月3日
下一篇 2020年6月4日

相关推荐

  • 深入理解java虚拟机第三版读书笔记01

    做笔记之前的感言 谈到《深入理解java虚拟机》,在业内可太有名了,是国内的一位大神写的一本关于java虚拟机的畅销书,基本上对java稍有深入的程序员都听说过这本书。不过遗憾的是…

    2020年1月4日
    0310
  • String s = new String("123");创建了几个String对象?

    提要 最近复习看到一道题目很有意思啊: String s = new String("123"); 问这样一行代码创建了几个String对象? 乍一看我其实以为和JDK的版本有关系…

    Java 2020年5月24日
    0580
  • ArrayList源码分析

    总结 总结放前面防止太长不看: ArrayList内部是用数组实现的。 如果使用无参构造函数建立ArrayList,在添加第一个元素的时候会分配10个元素的空间。 ArrayLis…

    2019年11月22日
    0160
  • 深入理解java虚拟机第三版读书笔记08

    以下是第七章 虚拟机类加载机制的内容 概述 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,…

    2020年1月22日
    0310
  • Java线程池详解

    线程池就是享元模式和生产者消费者模式的应用 动手实现线程池 步骤1:自定义拒绝策略接口 @FunctionalInterface // 拒绝策略 interface RejectP…

    2020年2月3日
    0320
  • 深入理解java虚拟机第三版读书笔记06

    附: Java虚拟机规范-Class文件格式:JDK8 Java虚拟机规范-Class文件格式:JDK13 以下是第六章 类文件结构的内容 Class类文件的结构 Class文件是…

    Java 2020年1月18日
    0180
  • 阻塞队列BlockingQueue详解

    阻塞队列是生产者消费者模式的经典体现。 我们在曾在Java线程池详解中自己实现过一个阻塞队列,这篇文章我们来研究一下JDK中的阻塞队列: BlockingQueue接口主要方法 抛…

    Java 2020年2月14日
    0600
  • Servlet4.0初识总结

    JavaEE8 JavaEE8,是自2013年6月Java企业版的首次更新。JAVAEE8提供了一些新的API,提供了对HTTP/2的新支持。 Servlet4.0 Servlet…

    Java 2019年11月28日
    02180
  • JDK8-Stream流库详解

    流提供了一种让我们可以在比集合更高的概念级别上指定计算的数据视图。通过使用流,我们可以说明想要完成什么任务,而不是说明如何去实现它。 流的创建 Collection.stream(…

    Java 2020年2月11日
    0150
  • 详解java中的unicode编码(码点)

    致谢: 本文参考网页:Unicode字符集以及UTF-8,UTF-16编码的总结 - vcj1009784814的博客 - CSDN博客 Unicode unicode的码点从U+…

    2019年11月25日
    0900

发表回复

登录后才能评论