Optional 详细用法

2023-11-04

1:Optional 是一个对象容器,具有以下两个特点

  • 提示用户要注意该对象有可能为null

  • 简化if else代码

Optional.empty(): 创建一个空的 Optional 实例

Optional.of(T t):创建一个 Optional 实例,当 t为null时抛出异常

//调用工厂方法创建Optional实例
Optional<String> name = Optional.of("Sanaulla");
//控制台打印输出Sanaulla
System.out.println(name.get());
//传入参数为null,抛出NullPointerException.
Optional<String> someNull = Optional.of(null);

Optional.ofNullable(T t):创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例

//ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况,如果指定的值为null,则返回一个空的Optional
//下面创建了一个不包含任何值的Optional实例
//例如,值为'null'
Optional empty = Optional.ofNullable(null);
//通过isPresent()方法返回false为空,true非空
if (empty.isPresent()) {
	System.out.println(empty.get());
} else {
	System.out.println("值为空");
}

2. 获取:

get():获取optional实例中的对象,当optional 容器为空时报错

3. 判断:

  • isPresent():判断optional是否为空,如果空则返回false,否则返回true
//isPresent方法用来检查Optional实例中是否包含值
if (name.isPresent()) {
  //在Optional实例内调用get()返回已存在的值
  System.out.println(name.get());//输出Sanaulla
}
  • ifPresent(Consumer c):如果optional不为空,则将optional中的对象传给Comsumer函数
//ifPresent方法接受lambda表达式作为参数。
//lambda表达式对Optional的值调用consumer进行处理。
		Optional<String> optional = Optional.of("Hello");
        optional.ifPresent(s -> {
            s = s + "world";
           //打印Helloworld
            System.out.println(s);
        });
        //打印Hello
        System.out.println(optional.get());
//通过ifPresent修改的值,再次通过get获取的时候不会改变
  • 设置(获取)默认值,有时候,我们在创建(获取) Optional 对象的时候,需要一个默认值,orElse() 和 orElseGet() 方法就派上用场了(类似三目运算符)
  • orElse() 方法用于返回包裹在 Optional 对象中的值,如果该值不为 null,则返回;否则返回默认值。该方法的参数类型和值得类型一致(类似三目运算符)
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("沉默王二");
System.out.println(name); // 输出:沉默王二
String nullName = "小王";
String name = Optional.ofNullable(nullName).orElse("沉默王二");
System.out.println(name); // 输出:小王
  • orElseGet() 方法与 orElse() 方法类似,但参数类型不同。如果 Optional 对象中的值为 null,则执行参数中的函数
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(()->"沉默王二");
System.out.println(name); // 输出:沉默王二
  • 从输出结果以及代码的形式上来看,这两个方法极其相似,这不免引起我们的怀疑,Java 类库的设计者有必要这样做吗?
  • 假设现在有这样一个获取默认值的方法,很传统的方式
public static String getDefaultValue() {
    System.out.println("getDefaultValue");
    return "沉默王二";
}
  • 然后,通过 orElse() 方法和 orElseGet() 方法分别调用 getDefaultValue() 方法返回默认值
public static void main(String[] args) {
    String name = null;
    System.out.println("orElse");
    String name2 = Optional.ofNullable(name).orElse(getDefaultValue());

    System.out.println("orElseGet");
    String name3 = Optional.ofNullable(name).orElseGet(Demo::getDefaultValue);
}
  • 注:类名 :: 方法名是 Java 8 引入的语法,方法名后面是没有 () 的,表明该方法并不一定会被调用
  • 输出结果如下所示:
orElse
getDefaultValue

orElseGet
getDefaultValue

- 输出结果是相似的,没什么太大的不同,这是在 Optional 对象的值为 null 的情况下。假如 Optional 对象的值不为 null 呢?

public static void main(String[] args) {
    String name = "沉默王三";
    System.out.println("orElse");
    String name2 = Optional.ofNullable(name).orElse(getDefaultValue());

    System.out.println("orElseGet");
    String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue);
}
  • 输出结果如下所示:
orElse
getDefaultValue
orElseGet
  • orElseGet() 没有去调用 getDefaultValue()。orElseGet方法的性能更佳
  • orElseGet() 直观从语义上来看,get() 方法才是最正宗的获取 Optional 对象值的方法,但很遗憾,该方法是有缺陷的,因为假如 Optional 对象的值为 null,该方法会抛出 NoSuchElementException 异常。这完全与我们使用 Optional 类的初衷相悖
public class GetOptionalDemo {
    public static void main(String[] args) {
        String name = null;
        Optional<String> optOrNull = Optional.ofNullable(name);
        System.out.println(optOrNull.get());
    }
}
  • 这段程序在运行时会抛出异常:
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:141)
	at com.cmower.dzone.optional.GetOptionalDemo.main(GetOptionalDemo.java:9)
  • 尽管抛出的异常是 NoSuchElementException 而不是 NPE,但在我们看来,显然是在“五十步笑百步”。建议 orElseGet() 方法获取 Optional 对象的值
  • orElse(T other):如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值
//如果值不为null,orElse方法返回Optional实例的值。
//如果为null,返回传入的消息。
//输出:There is no value present!
System.out.println(empty.orElse("There is no value present!"));
//输出:Sanaulla
System.out.println(name.orElse("There is some value!"));
  • orElseGet(Supplier other):如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other

  • orElseThrow(Supplier exception):如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常

4. 过滤:

filter(Predicate p):如果optional不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional

//filter方法检查给定的Option值是否满足某些条件。
//如果满足则返回同一个Option实例,否则返回空Optional。
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));//输出Sanaulla

//另一个例子是Optional值不满足filter指定的条件。
Optional<String> anotherName = Optional.of("Sana");
Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
//输出:name长度不足6字符
System.out.println(shortName.orElse("The name is less than 6 characters"));

5. 映射:

  • map(Function<T, U> mapper):如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中。
//map方法执行传入的lambda表达式参数对Optional实例的值进行修改。
//为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));
  • flatMap(Function< T,Optional< U >> mapper):跟上面一样,在optional不为空的情况下,将对象t映射成另外一个optional

  • 区别:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional

//flatMap与map(Function)非常类似,区别在于传入方法的lambda表达式的返回类型。
//map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。 
//但flatMap方法中的lambda表达式返回值必须是Optionl实例。 
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));//输出SANAULLA

6:实例演示- Optional 的三种构造方式: Optional.of(obj), Optional.ofNullable(obj) 和明确的 Optional.empty(),生成user

  • 存在即返回, 无则提供默认值
Optional<String> optional = Optional.of("Hello");
//打印Hello
System.out.println(user.orElse(null);  

//而不是 
return user.isPresent() ? user.get() : null;


  • 存在即返回, 无则由函数来产生
return user.orElseGet(() -> fetchAUserFromDatabase()); 

//而不要 
return user.isPresent() ? user: fetchAUserFromDatabase();

  • 存在才对它做点什么
user.ifPresent(System.out::println);

//而不要下边那样
if (user.isPresent()) {
  System.out.println(user.get());
}


  • map 函数隆重登场
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())

//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
  return user.get().getOrders();
} else {
  return Collections.emptyList();
}

使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等这样的方法.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Optional 详细用法 的相关文章

随机推荐

  • 【Vue.js学习】三、Vue案例:计数器

    Vue js学习 三 Vue案例 计数器 一 HTML页面 二 Js代码 三 效果 实现计数器 要用到Vue的监听语法 v on click 函数名 声明函数后 在js中写入 methods 进行对函数的控制 下面进行详细解释 一 HTML
  • 成功转行Python工程师,年薪35W+,吐血整理

    这是给转行做Python的小白的参考 无论是从零开始 或者是转行的朋友来说 这都是值得一看的 也是可以作为一种借鉴吧 而且我决定转行IT 互联网 行业 其实理由也很简单 不用动体力 大多数动的是脑力工作 而且现在的互联网趋势很明显 再者看到
  • THINKPHP5.1在windows系统下,安装GateWayWorker

    一 GateWayWorker简单介绍 a GatewayWorker基于Workerman开发的一个项目框架 用于快速开发TCP长连接应用 例如app推送服务端 即时IM服务端 游戏服务端 物联网 智能家居等等 b 如果你的项目是长连接并
  • 中科大、字节新作

    导读 最近 大型语言模型 Large Language Models LLMs 相关研究和落地取得了显著进展 为实现通用人工智能 AGI 迈出了重要步伐 并在各种语言应用中表现卓越 例如 2022 年底发布的 ChatGPT 能够基于在预训
  • 蓝桥杯算法训练VIP-单词接龙

    题目 题目链接 题解 DFS 真没想到居然是暴力搜索 感觉时间复杂度根本不允许啊 大致思路 每次递归都遍历全部字符串 对于每个字符串 枚举要匹配的长度 在此长度下依次匹配原串的尾与遍历到的字符串的头 完全相同说明可以匹配当前长度 就继续深搜
  • 20060122: 差点被偷

    昨天下班回去 车上比较挤 一中年男子掏我左上衣口袋 我转过身去 把口袋拉链拉起来 那男的又凑到我左边 右手拿把伞伸到我口袋前面 为的是挡住我前面坐着的乘客的视线 一个比较年轻的 站在我右后方 左手拿一块纸板挡住 右手开始拉我口袋拉链 我火来
  • MySQL数据库查询练习(子查询分步教程)

    注 数据库表格附录在文末 1 与张三同乡的男生姓名 step1 SELECT snativeplace FROM student WHERE sname 张三 step2 SELECT sname FROM student WHERE ss
  • C++11 智能指针

    此篇均参考C Primer第五版 为了更容易更安全的使用动态内存 C 11提供了两种智能指针 来管理动态对象 智能指针行为类似于常规指针 重要的区别在于它负责自动释放所指向的对象 shared ptr允许多个指针指向同一个对象 unique
  • Android自定义NoticeInfo实现顶部消息提示

    对于顶部消息提示功能 本文采用自定义NoticeInfo类 实现使用时只需要写一行代码 非常方便 一 效果如图所示 二 使用方法 只需要加入下面这8个文件 后面附有源码 即可使用 非常方便 使用示例 三 要加入的8个文件源代码如下 1 No
  • window下移动设备/硬盘报错位置不可用

    移动硬盘指示灯亮 但电脑上不显示 报错信息 无法访问E 参数错误 报错原因 移动硬盘打不开提示参数错误 是因为这个H盘的文件系统内部结构损坏导致的 要怎么恢复里面的数据呢 https jingyan baidu com article cb
  • java 生成条形码_JAVA 生成扫描条形码

    声明 转载为个人学习收藏 如有侵权 请及时联系本人删除 转载地址 https www cnblogs com MariaWang p 10837641 html 条形码是一种可视化 机器可读的数据 这些数据通常描述了携带该条码的物品的相关信
  • WCE下创建MFC的COM对象及使用方法(一)

    转载请标明是引用于 http blog csdn net chenyujing1234 平台 VS2005 MIPSSDK 例子代码 http www rayfile com zh cn files 7020e9b8 7240 11e1 b
  • 百度地图的基本知识与使用

    一 解释 LBS LocationBusinessServer基于定义位置的商业服务 二 使用步骤 1 登录注册 获取秘钥AK 2引入百度地图js 3创建地图的容器 div div 4初始化地图 var map new BMap Map c
  • 【安卓逆向】360加固-脱壳修复

    最近花了一些时间学习逆向脱壳 这方面一直投入的时间比较少 样本经过某加固宝进行加固 这里简单记录一下脱壳过程和思路 感谢某数字公司对安全加固的无私贡献 让我有机会小小的提高一下这方面的技能 安卓逆向交流学习qq 3251901516 vx
  • 【编程之路(003)】循环语句(for,while,do while语句)(C语言实现)

    目录 总体介绍 引言 for语句 基本语法 具体使用 for循环中的break和continue while语句 基本语法 具体使用 while语句中的break和continue do while 循环 具体使用 while语句中的bre
  • vc入门

    一 VC是什么 学VC是学什么 首先VC是一个软件 IDE集成开发环境 编译 编辑 调试 C和C 但C 中的有些特性是不用的 例如I O流 多态继承 WindowsSDK 软件开发工具 VC的灵魂 MFC 微软基础类库 ATL Active
  • php mail方法_php邮件发送的两种方式

    这篇文章研究的主要内容就是使用PHP来发送电子邮件 总结为以下两种方法 一 使用PHP内置的mail 函数 to test 163 com 收件人 subject Test 主题 message This is a test mail 正文
  • geopy 库 ConfigurationError 错误

    错误详情 geopy exc ConfigurationError Using Nominatim with default or sample user agent geopy 2 2 0 is strongly discouraged
  • LeetCode每日一练 —— 160. 相交链表

    前言 Wassup guys 我是Edison 今天是 LeetCode 上的 leetcode 160 相交链表 Let s get it 文章目录 1 题目分析 2 思路分析 判断相交 求出交点 实现步骤 3 代码实现 1 题目分析 给
  • Optional 详细用法

    1 Optional 是一个对象容器 具有以下两个特点 提示用户要注意该对象有可能为null 简化if else代码 Optional empty 创建一个空的 Optional 实例 Optional of T t 创建一个 Option