JAVA 8 Optional类介绍及其源码

简介:

什么是Optional对象

Java 8中所谓的Optional对象,即一个容器对象,该对象可以包含一个null或非null值。如果该值不为null,则调用isPresent()方法将返回true,且调用get()方法会返回该值。

另外,该对象还有其它方法:

如可以使用orElse()方法给Optional对象设定默认值(当值为null时,会使用默认值);

使用ifPresent()方法来执行一段代码(当值不为null时,执行代码段)。

Optional主要被用于Java 8的Stream中,简单举个例子:

复制代码
package optional;

import java.util.Optional;
import java.util.stream.Stream;

public class Snippet
{
    public static void main(String[] args)
    {
        Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");
        
        Optional<String> startswl = names.filter(name -> name.startsWith("L")).findFirst();
        
        //判断是否不为null
        if(startswl.isPresent()){
            System.out.println(startswl.get());
        }
        
        //if值为null:打印“null”;if值不为null:打印原值
        System.out.println(startswl.orElse("null"));

        //if值不为null,执行Lambda表达式
        startswl.ifPresent(name -> {
            String s = name.toUpperCase();
            System.out.println(s);
        });
    }
}
复制代码

使用Optional对象的好处

减少NullPointerException异常

写出更加优雅的代码

源码及示例

Optional类的属性和方法如下:

 

我们一个个看,先看两个成员属性;

成员属性

如下,一个是EMPTY常量,即存放空值的Optional对象,另一个是value,即被存放的值,可为null或非null值;

复制代码
    /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * If non-null, the value; if null, indicates no value is present
     */
    private final T value;
复制代码

构造方法

两个构造方法,注意都是私有的

1、创建一个包含空值的Optional对象;

2、创建一个非空值的Optional对象;

    private Optional() {
        this.value = null;
    }
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

empty()方法

这个方法很简单,作用是返回一个Optional实例,里面存放的value是null,源码如下:

    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

of(T value)方法

很简单,就是返回一个包含非空值的Optional对象

    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

ofNullable(T value)方法

 很简单,返回一个可以包含空值的Optional对象

    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

get()方法

 得到Optional对象里的值,如果值为null,则抛出NoSuchElementException异常

    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

isPresent()方法

很简单,判断值是否不为null

    public boolean isPresent() {
        return value != null;
    }

ifPresent(Consumer<? super T> consumer)方法

 当值不为null时,执行consumer

    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

举个例子,ifPresent方法执行Lambda表达式,将值转换为大写并打印:

复制代码
package optional;

import java.util.Optional;

public class Snippet
{
    public static void main(String[] args)
    {
        Optional<String> test = Optional.ofNullable("abcDef");
        
        //值不为null,执行Lambda表达式,
        test.ifPresent(name -> {
            String s = name.toUpperCase();
            System.out.println(s);
        });
        //打印ABCDEF
    }
}
复制代码

filter(Predicate<? super T> predicate)方法

看方法名就知道,该方法是过滤方法,过滤符合条件的Optional对象,这里的条件用Lambda表达式来定义,

如果入参predicate对象为null将抛NullPointerException异常,

如果Optional对象的值为null,将直接返回该Optional对象,

如果Optional对象的值符合限定条件(Lambda表达式来定义),返回该值,否则返回空的Optional对象

源码如下:

复制代码
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }
复制代码

使用示例:

复制代码
package optional;

import java.util.Optional;

public class Snippet
{
    public static void main(String[] args)
    {
        Optional<String> test = Optional.ofNullable("abcD");
        
        //过滤值的长度小于3的Optional对象
        Optional<String> less3 = test.filter((value) -> value.length() < 3);
        //打印结果
        System.out.println(less3.orElse("不符合条件,不打印值!"));
    }
}
复制代码

map(Function<? super T, ? extends U> mapper)方法

 前面的filter方法主要用于过滤,一般不会修改Optional里面的值,map方法则一般用于修改该值,并返回修改后的Optional对象

如果入参mapper对象为null将抛NullPointerException异常,

如果Optional对象的值为null,将直接返回该Optional对象,

最后,执行传入的lambda表达式,并返回经lambda表达式操作后的Optional对象

复制代码
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
复制代码

使用示例:

复制代码
package optional;

import java.util.Optional;

public class Snippet
{
    public static void main(String[] args)
    {
        Optional<String> test = Optional.ofNullable("abcD");
        
        //将值修改为大写
        Optional<String> less3 = test.map((value) -> value.toUpperCase());
        //打印结果 ABCD
        System.out.println(less3.orElse("值为null,不打印!"));
    }
}
复制代码

flatMap(Function<? super T, Optional<U>> mapper)方法

flatMap方法与map方法基本一致,唯一的区别是,

如果使用flatMap方法,需要自己在Lambda表达式里将返回值转换成Optional对象,

而使用map方法则不需要这个步骤,因为map方法的源码里已经调用了Optional.ofNullable方法;

源码:

复制代码
    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
复制代码

使用示例:

复制代码
package optional;

import java.util.Optional;

public class Snippet
{
    public static void main(String[] args)
    {
        Optional<String> test = Optional.ofNullable("abcD");
        
        //使用flatMap,将值修改为大写
        Optional<String> less3 = test.flatMap((value) -> Optional.ofNullable(value.toUpperCase()));
        //使用map,将值修改为大写
        //Optional<String> less3 = test.map((value) -> value.toUpperCase());
        
        //打印结果 ABCD
        System.out.println(less3.orElse("值为null,不打印!"));
    }
}
复制代码

orElse(T other)方法

很简单,当值为null时返回传入的值,否则返回原值;

源码:

    public T orElse(T other) {
        return value != null ? value : other;
    }

orElseGet(Supplier<? extends T> other)方法

功能与orElse(T other)类似,不过该方法可选值的获取不是通过参数直接获取,而是通过调用传入的Lambda表达式获取

源码:

    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

使用示例:

复制代码
package optional;

import java.util.Optional;

public class Snippet
{
    public static void main(String[] args)
    {
        Optional<String> test = Optional.ofNullable(null);

        System.out.println(test.orElseGet(() -> "hello"));
        //将打印hello
    }
}
复制代码

orElseThrow(Supplier<? extends X> exceptionSupplier)方法

当遇到值为null时,根据传入的Lambda表达式跑出指定异常

源码

复制代码
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
复制代码

使用示例:

复制代码
package optional;

import java.util.Optional;

public class Snippet
{
    public static void main(String[] args)
    {
        Optional<String> test = Optional.ofNullable(null);

        //这里的Lambda表达式为构造方法引用
        System.out.println(test.orElseThrow(NullPointerException::new));
        //将打印hello
    }
}
复制代码
本文转自风一样的码农博客园博客,原文链接:http://www.cnblogs.com/chenpi/p/5923829.html,如需转载请自行联系原作者
相关文章
|
8天前
|
数据采集 运维 前端开发
【Java】全套云HIS源码包含EMR、LIS (医院信息化建设)
系统技术特点:采用前后端分离架构,前端由Angular、JavaScript开发;后端使用Java语言开发。
28 5
|
10天前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
26 1
|
10天前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
22 0
java基础(13)String类
|
3天前
|
Java API
Java的日期类都是怎么用的
【10月更文挑战第1天】本文介绍了 Java 中处理日期和时间的三个主要类:`java.util.Date`、`java.util.Calendar` 和 `java.time` 包下的新 API。`Date` 类用于表示精确到毫秒的瞬间,可通过时间戳创建或获取当前日期;`Calendar` 抽象类提供丰富的日期操作方法,如获取年月日及时区转换;`java.time` 包中的 `LocalDate`、`LocalTime`、`LocalDateTime` 和 `ZonedDateTime` 等类则提供了更为现代和灵活的日期时间处理方式,支持时区和复杂的时间计算。
26 14
|
6天前
|
传感器 监控 数据可视化
【Java】智慧工地解决方案源码和所需关键技术
智慧工地解决方案是一种新的工程全生命周期管理理念。它通过使用各种传感器、数传终端等物联网手段获取工程施工过程信息,并上传到云平台,以保障数据安全。
28 7
|
7天前
|
安全 Java 编译器
java访问类字段
java访问类字段
|
9天前
|
Java
java的class类
java的class类
18 5
|
10天前
|
Java 数据处理
Java Scanner 类详解
`Scanner` 类是 Java 中 `java.util` 包提供的强大工具,用于从多种输入源(如键盘、文件、字符串)读取数据。本文详细介绍如何创建 `Scanner` 对象并使用其常用方法(如 `next()`, `nextInt()`, `nextLine()` 等)。通过示例代码展示如何从标准输入、字符串及文件中读取数据,并进行输入验证。使用时需注意关闭 `Scanner` 以释放资源,并确保输入类型匹配,避免异常。掌握 `Scanner` 可显著提升程序的数据处理能力。
|
机器人 Java
深度解析 Java 的 Optional 类(下)
深度解析 Java 的 Optional 类(下)
110 0
深度解析 Java 的 Optional 类(下)
|
Java
深度解析 Java 的 Optional 类(上)
深度解析 Java 的 Optional 类(上)
131 0
深度解析 Java 的 Optional 类(上)
下一篇
无影云桌面