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,如需转载请自行联系原作者
相关文章
|
9天前
|
Java 开发者
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
32 0
|
15天前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:输入与输出:Scanner与System类
你是否也经历过这些崩溃瞬间?三天教程连`i++`和`++i`都说不清,面试时`a==b`与`equals()`区别大脑空白,代码总是莫名报NPE。这个系列就是为你打造的Java「速效救心丸」!每天1分钟,地铁通勤、午休间隙即可学习。直击高频考点和实际开发中的“坑位”,拒绝冗长概念,每篇都有可运行代码示例。涵盖输入输出基础、猜数字游戏、企业编码规范、性能优化技巧、隐藏技能等。助你快速掌握Java核心知识,提升编程能力。点赞、收藏、转发,助力更多小伙伴一起成长!
41 19
|
9天前
|
存储 监控 安全
重学Java基础篇—类的生命周期深度解析
本文全面解析了Java类的生命周期,涵盖加载、验证、准备、解析、初始化、使用及卸载七个关键阶段。通过分阶段执行机制详解(如加载阶段的触发条件与技术实现),结合方法调用机制、内存回收保护等使用阶段特性,以及卸载条件和特殊场景处理,帮助开发者深入理解JVM运作原理。同时,文章探讨了性能优化建议、典型异常处理及新一代JVM特性(如元空间与模块化系统)。总结中强调安全优先、延迟加载与动态扩展的设计思想,并提供开发建议与进阶方向,助力解决性能调优、内存泄漏排查及框架设计等问题。
29 5
|
19天前
|
前端开发 JavaScript Java
[Java计算机毕设]基于ssm的OA办公管理系统的设计与实现,附源码+数据库+论文+开题,包安装调试
OA办公管理系统是一款基于Java和SSM框架开发的B/S架构应用,适用于Windows系统。项目包含管理员、项目管理人员和普通用户三种角色,分别负责系统管理、请假审批、图书借阅等日常办公事务。系统使用Vue、HTML、JavaScript、CSS和LayUI构建前端,后端采用SSM框架,数据库为MySQL,共24张表。提供完整演示视频和详细文档截图,支持远程安装调试,确保顺利运行。
60 17
|
16天前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
44 11
|
9天前
|
安全 IDE Java
重学Java基础篇—Java Object类常用方法深度解析
Java中,Object类作为所有类的超类,提供了多个核心方法以支持对象的基本行为。其中,`toString()`用于对象的字符串表示,重写时应包含关键信息;`equals()`与`hashCode()`需成对重写,确保对象等价判断的一致性;`getClass()`用于运行时类型识别;`clone()`实现对象复制,需区分浅拷贝与深拷贝;`wait()/notify()`支持线程协作。此外,`finalize()`已过时,建议使用更安全的资源管理方式。合理运用这些方法,并遵循最佳实践,可提升代码质量与健壮性。
20 1
|
7天前
|
Java
java常见的集合类有哪些
Map接口和Collection接口是所有集合框架的父接口: 1. Collection接口的子接口包括:Set接口和List接口 2. Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及 Properties等 3. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等 4. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
|
13天前
|
JavaScript Java Docker
干货含源码!如何用Java后端操作Docker(命令行篇)
只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
安全 Java
Java并发编程笔记之CopyOnWriteArrayList源码分析
并发包中并发List只有CopyOnWriteArrayList这一个,CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行修改操作和元素迭代操作都是在底层创建一个拷贝数组(快照)上进行的,也就是写时拷贝策略。
19578 0
|
Java 安全
Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 ReentrantLock 满足不了需求,所以 ReentrantReadWriteLock 应运而生,ReentrantReadWriteLock 采用读写分离,多个线程可以同时获取读锁。
3163 0