当前位置: 首页 > news >正文

Java8 特性(二):Optional 相关操作

一、Optional 简介

Optional 是一个容器对象,可以存储对象、字符串等值,当然也可以存储 null 值。Optional 提供很多有用的方法,能帮助我们将 Java 中的对象等一些值存入其中,这样我们就不用显式进行空值检测,使我们能够用少量的代码完成复杂的流程。

比如它提供了:

  • of() 方法,可以将值存入 Optional 容器中,如果存入的值是 null 则抛异常。
  • ofNullable() 方法,可以将值存入 Optional 容器中,即使值是 null 也不会抛异常。
  • get() 方法,可以获取容器中的值,如果值为 null 则抛出异常。
  • getElse() 方法,可以获取容器中的值,如果值为 null 则返回设置的默认值。
  • isPresent() 方法,该方法可以判断存入的值是否为空。
  • …等等一些其它常用方法,下面会进行介绍。

可以说,使用 Optional 可以帮助我们解决业务中,减少值动不动就抛出空指针异常问题,也减少 null 值的判断,提高代码可读性等
在这里插入图片描述



二、Optional 类描述

  • Optional 类所在包: java.util.Optional
  • Optional 类声明: public final class Optional extends Object
  • Optional 类方法: public Optional filter(Predicate<? super T> predicate)
方法名称修饰符、返回类型方法描述
empty()static Optional方法描述
equals(Object obj)boolean判断其他对象是否等于 Optional。
filter(Predicate<? super T> predicate)Optional如果有值并且满足断言条件返回包含该值的 Optional,否则返回空 Optional。
get()T如果在这个 Optional 中包含这个值则返回值,否则抛出 NoSuchElementException 异常。
hashCode()int返回存在值的哈希码,如果值不存在则返回 0。
ifPresent(Consumer<? super T> consumer)void如果值存在则使用该值调用 consumer , 否则不做任何事情。
isPresent()boolean如果值存在则方法会返回 true,否则返回 false。
flatMap(Function<? super T,Optional> mapper)Optional如果值存在,返回基于 Optional 包含的映射方法的值,否则返回一个空的 Optional。
map(Function<? super T,? extends U> mapper)Optional如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
of(T value)static Optional返回一个指定非 null 值的 Optional。
ofNullable(T value)static Optional果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
orElse(T other)T如果该值存在就直接返回, 否则返回指定的其它值。
orElseGet(Supplier<? extends T> other)T如果该值存在就返回值,否则触发 other,并返回 other 调用的结果。
orElseThrow(Supplier<? extends X> exceptionSupplier) T如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常。
toString()String返回一个 Optional 的非空字符串,用来调试。

官网地址为:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html



三、基本使用

1、静态方法 Optional.of()

  • 方法作用: 为指定的值创建一个指定非 null 值的 Optional。
  • 方法描述: of 方法通过工厂方法创建 Optional 实例,需要注意的是传入的参数不能为 null,否则抛出 NullPointerException。
  • 返回类型: Optional
  • 示例代码:
public static void main(String[] args) {
  // 传入正常值,正常返回一个 Optional 对象
  Optional<String> optional1 = Optional.of("value");

  // 传入参数为 null,抛出 NullPointerException.
  Optional<String> optional2 = Optional.of(null);
}

2、静态方法 Optional.ofNullable()

  • 方法作用: 为指定的值创建一个 Optional 对象,如果指定的参数为 null,不抛出异常,直接则返回一个空的 Optional 对象。
  • 方法描述: ofNullable 方法是和 of 方式一样,都是用于创建 Optional 对象,只是传入的参数 null 时,会返回一个空的 Optional 对象,而不会抛出 NullPointerException 异常。
  • 返回类型: Optional
  • 示例代码:
public static void main(String[] args) {
  // 传入正常值,正常返回一个 Optional 对象
  Optional<String> optional1 = Optional.ofNullable("value");

  // 传入 null 参数,正常返回 Optional 对象
  Optional<String> optional2 = Optional.ofNullable(null);
}

3、对象方法 get()

  • 方法作用: 如果 Optional 有值则将其返回,否则抛出 NoSuchElementException 异常。
  • 方法描述: get 方法内部实现其实就是判断 Otpional 对象中的 value 属性是否为 null,如果是就抛出 NoSuchElementException 异常,否则返回这个 value 值。
  • 返回类型: T
  • 示例代码:
public static void main(String[] args) {
  // 传入正常值,正常返回一个 Optional 对象,并使用 get 方法获取值
  Optional<String> optional1 = Optional.ofNullable("value");
	System.out.println(optional1.get());

	// 传入参数为 null 生成一个 Optional 对象,并使用 get 方法获取值
	Optional<String> optional2 = Optional.ofNullable(null);
	// 这里取值的时候会失败,抛出空指针异常
	System.out.println(optional2.get());
}

Optional 中的值为null的时候,直接使用get方法取值会抛出空指针异常,可与方法 isPresent() 结合使用或者是使用其他方式,如:orElse()。

4、对象方法 isPresent()

  • 方法作用: 如果值存在则方法会返回 true,否则返回 false。
  • 方法描述: 该方法其实就是用于判断创建 Optional 时传入参数的值是否为空,实现代码就简单一行,即 value != null 所以如果不为空则返回 true,否则返回 false。
  • 返回类型: boolean
  • 示例代码:
public static void main(String[] args) {
  // 传入正常值,正常返回一个 Optional 对象,并使用 isPresent 方法
  Optional<String> optional1 = Optional.ofNullable("value");
  System.out.println("传入正常值返回:" + optional1.isPresent());

  // 传入参数为 null 生成一个 Optional 对象,并使用 isPresent 方法
  Optional<String> optional2 = Optional.ofNullable(null);
  System.out.println("传入 null 值返回:" + optional2.isPresent());
}

5、对象方法 orElse()

  • 方法作用: 如果该值存在就直接返回, 否则返回指定的其它值。
  • 方法描述: orElse 方法实现很简单,就是使用三目表达式对传入的参数值进行 null 验证,即 value != null ? value : other; 如果为 null 则返回 true,否则返回 false。
  • 返回类型: T
  • 示例代码:
public static void main(String[] args) {
  // 传入正常参数,获取一个 Optional 对象,并使用 orElse 方法设置默认值
  Optional<String> optional1 = Optional.ofNullable("value");
  Object object1 = optional1.orElse("default");
  System.out.println("如果值不为空:" + object1);

  // 传入 null 参数,获取一个 Optional 对象,并使用 orElse 方法设置默认值
  Optional<String> optional2 = Optional.ofNullable(null);
  Object object2 = optional2.orElse("default");
  System.out.println("如果值为空:" + object2);
}

6、对象方法 orElseGet()

  • 方法作用: 如果该值存在就返回值,否则触发 other,并返回 other 调用的结果。
  • 方法描述: orElseGet 方法和 orElse 方法类似,都是在 Optional 值为空时,返回一个默认操作,只不过 orElse 返回的是默认值,而 orElseGet 是执行 lambda 表达式,然后返回 lambda 表达式执行后的结果。
  • 返回类型: T
  • 示例代码:
public static void main(String[] args) {
  // 传入正常参数,获取一个 Optional 对象,并使用 orElse 方法设置默认值
  Optional<String> optional1 = Optional.ofNullable("value");
  Object object1 = optional1.orElseGet(() -> {
    System.out.println("这里可以执行代码逻辑:optional1");
    return "code default";
  });
  System.out.println("输出的值为:" + object1);

  // 传入 null 参数,获取一个 Optional 对象,并使用 orElse 方法设置默认值
  Optional<String> optional2 = Optional.ofNullable(null);
  Object object2 = optional2.orElseGet(() -> {
    System.out.println("这里可以执行代码逻辑:optional2");
    return "code default";
  });
  System.out.println("输出的值为:" + object2);
}

其他orElseXxx()系列的方法使用类似。

7、对象方法 map()

  • 方法作用: 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
  • 方法描述: map 方法主要用于获取某个对象中的某个属性值的 Optional 对象时使用。map 方法调用时,首先验证传入的映射函数是否为空,如果为空则抛出异常。然后,再检测 Optional 的 value 是否为空,如果是,则返回一个空 value 的 Optional 对象。如果传入的映射函数和 Optinal 的 value 都不为空,则返回一个带 value 对象属性的 Optional 对象。
  • 返回类型: Optional
  • 示例代码:
public static void main(String[] args) {
  // 创建 map 对象
  Map<String, String> userMap = new HashMap<>();
  userMap.put("name1", "value");
  userMap.put("name2", null);

  // 传入 Map 对象参数,获取一个 Optional 对象,获取 name1 属性
  Optional<String> optional1 = Optional.of(userMap).map(value -> value.get("name1"));

  // 传入 Map 对象参数,获取一个 Optional 对象,获取 name2 属性
  Optional<String> optional2 = Optional.of(userMap).map(value -> value.get("name2"));

  // 传入 Map 对象参数,获取一个 Optional 对象,获取 name3 属性
  Optional<String> optional3 = Optional.of(userMap).map(value -> value.get("name3"));

  // 获取 Optional 的值,这里使用的是orElse()方法
  System.out.println("获取的 name1 的值:" + optional1.orElse("default"));
  System.out.println("获取的 name2 的值:" + optional2.orElse("default"));
  System.out.println("获取的 name3 的值:" + optional3.orElse("default"));
}

8、对象方法 flatMap()

  • 方法作用: 如果值存在,返回基于 Optional 包含的映射方法的值,否则返回一个空的 Optional。
  • 方法描述: flatMap 方法和 map 方法类似,唯一的不同点就是 map 方法会对返回的值进行 Optional 封装,而 flatMap 不会,它需要手动执行 Optional.of 或 Optional.ofNullable 方法对 Optional 值进行封装
  • 返回类型: Optional
  • 示例代码:
public static void main(String[] args) {
  // 创建 map 对象
  Map<String, String> userMap = new HashMap<>();
  userMap.put("name", "张三");
  userMap.put("sex", "男");

  // 传入 Map 对象参数,获取一个 Optional 对象
  Optional<Map<String, String>> optional1 = Optional.of(userMap);

  // 使用 Optional 的 flatMap 方法,获取 Map 中的 name 属性
  // 然后通过获取的值手动创建一个新的 Optional 对象
  Optional<String> optional2 = optional1.flatMap(value -> Optional.ofNullable(value.get("name")));

  // 获取 Optional 的 value
  System.out.println("获取的 Optional 的值:" + optional2.get());
}

9、对象方法 filter()

  • 方法作用: 如果有值并且满足断言条件返回包含该值的 Optional,否则返回空 Optional。
  • 方法描述: filter 方法通过传入的限定条件对 Optional 实例的值进行过滤,如果 Optional 值不为空且满足限定条件就返回包含值的 Optional,否则返回空的 Optional。这里设置的限定条件需要使用实现了 Predicate 接口的 lambda 表达式来进行配置。
  • 返回类型: Optional
  • 示例代码:
public static void main(String[] args) {
  // 创建一个测试的 Optional 对象
  Optional<String> optional = Optional.ofNullable("value");
  // 调用 Optional 的 filter 方法,设置一个满足的条件,然后观察获取的 Optional 对象值是否为空
  Optional<String> optional1 = optional.filter((value) -> value.length() > 2);
  System.out.println("Optional 的值不为空::" + optional1.isPresent());

  // 调用 Optional 的 filter 方法,设置一个不满足的条件,然后观察获取的 Optional 对象值是否为空
  Optional<String> optional2 = optional.filter((value) -> value.length() < 2);
  System.out.println("Optional 的值不为空::" + optional2.isPresent());
}

10、对象方法 ifPresent()

  • 方法作用: 如果存在值,则使用该值调用指定的使用者,否则不执行任何操作。
  • 方法描述: 终止操作,如果存在值,就对其值做对应操作,不存在值则不处理。
  • 返回类型: void
  • 示例代码:
public static void main(String[] args) {
  // 原始数据
  List<UserInfo> dataList = new ArrayList<>();
  dataList.add(new UserInfo("张三"));
  dataList.add(new UserInfo("李四"));
  dataList.add(new UserInfo("王五"));

  Optional.ofNullable(dataList).ifPresent(list -> {
    list.forEach(e -> {
      e.setName(e.getName() + "aaa");
    });
  });
  dataList.forEach(System.out::println);
}


四、Optional 常用组合

在前面的介绍中已经说过 Optional 是个容器,它可用保存类型的 T 的值,即使 T 为 null 也可以使用 Optional 存储,这样就不用显示进行空值检测,防止空指针异常。

其次上面也介绍了 Optional 的各种方法,在实际使用中这些方法常常组合使用。且很多方法也常与 Lambda 表达式结合,获取我们想要的结果的值。

1、对集合中的对象属性进行过滤

创建一个 UserInfo 对象实体类,里面包含 name 属性:

class UserInfo {
    private String name;

    public UserInfo(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

创建 UserInfo 对象集合,测试通过 Optional 获取 name 属性值:

public class OptionalTest {
    public static void main(String[] args) {
        List<UserInfo> userList = getUserInfoList();

        // 创建用于存储姓名的集合
        List<String> nameList = new ArrayList<>();
        // 循环用户列表获取用户信息,值获取不为空且用户以 a 开头的姓名,
        // 如果不符合条件就设置默认值,最后将符合条件的用户姓名加入姓名集合
        for (UserInfo userInfo : userList) {
            nameList.add(Optional.ofNullable(userInfo).map(UserInfo::getName).filter(value -> value.startsWith("z")).orElse("不符合条件"));
        }

        // 输出名字集合中的值
        System.out.println("通过 Optional 过滤的集合输出:");
        nameList.stream().forEach(System.out::println);
    }

    private static List<UserInfo> getUserInfoList() {
        // 创建一个测试的用户集合
        List<UserInfo> userList = new ArrayList<>();

        // 创建几个测试用户
        UserInfo user1 = new UserInfo("zhangsan");
        UserInfo user2 = new UserInfo("lisi");
        UserInfo user3 = null;

        // 将用户加入集合
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);

        return userList;
    }
}

2、级联验证取值

可通过map()方法级联获取对象中的属性,避免每一步都做繁琐的空指针检验,如:

// A 对象中存在B对象,B对象中存在C集合,获取C集合的数据
A aObject = new A();
List<C> cList = Optional.of(aObject).map(A::getbObject).map(B::getcList).orElse(new ArrayList<>());

创建A、B、C三个类:

class A {
    private B bObject;

    public B getbObject() {
        return bObject;
    }

    public void setbObject(B bObject) {
        this.bObject = bObject;
    }
}

class B {
    private List<C> cList;

    public List<C> getcList() {
        return cList;
    }

    public void setcList(List<C> cList) {
        this.cList = cList;
    }
}

class C {
    private String name;

    public C(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

获取集合C

public class OptionalTest {
    public static void main(String[] args) {
        A aObject = getAObject();
        // 不确定 aObject 是否为空的话,可以使用 ofNullable() 方法
        List<C> cList = Optional.of(aObject).map(A::getbObject).map(B::getcList).orElse(new ArrayList<>());
        cList.stream().forEach(e -> {
            System.out.println(e.getName());
        });

        System.out.println("======");
        // B属性为空的时候,不会抛出空指针异常
        aObject.setbObject(null);
        List<C> cList1 = Optional.of(aObject).map(A::getbObject).map(B::getcList).orElse(new ArrayList<>());
        cList1.stream().forEach(e -> {
            System.out.println(e.getName());
        });
    }

    private static A getAObject() {
        C c1 = new C("张三");
        C c2 = new C("李四");
        C c3 = new C("王五");
        C c4 = new C(null);

        List<C> cList = Arrays.asList(c1, c2, c3, c4);

        B b = new B();
        b.setcList(cList);

        A a = new A();
        a.setbObject(b);

        return a;
    }
}

相关文章:

  • y119.第七章 服务网格与治理-Istio从入门到精通 -- Istio流量治理快速入门(五)
  • 以字符串的形式返回文件名扩展名
  • 机械硬盘数据拷贝
  • 计算机毕业设计java毕设项目之ssm中医药配方小程序
  • 【C++】内存管理 + 初识模板
  • 猿创征文|我的技术成长之路,一名Python学者在CSDN的蜕变
  • java基于ssm的高校人事员工工资管理系统
  • QML初学者教程
  • 速卖通详情接口接口调用示例
  • 记录Kettle连不上mysql8
  • 远程Debug远端服务器JVM配置
  • Java中的内部类,你真的理解吗
  • Home Depot 使用 SUSE Rancher 和 K3s 升级 2300 个零售边缘位置
  • 处方识别 易语言代码
  • 跟李沐学AI之多层感知机+深度学习计算
  • [Vue CLI 3] 配置解析之 css.extract
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Angular数据绑定机制
  • AWS实战 - 利用IAM对S3做访问控制
  • ES6简单总结(搭配简单的讲解和小案例)
  • Fastjson的基本使用方法大全
  • iOS | NSProxy
  • Java多线程(4):使用线程池执行定时任务
  • js递归,无限分级树形折叠菜单
  • laravel with 查询列表限制条数
  • rc-form之最单纯情况
  • scala基础语法(二)
  • Service Worker
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 每天10道Java面试题,跟我走,offer有!
  • 让你的分享飞起来——极光推出社会化分享组件
  • 网页视频流m3u8/ts视频下载
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • ionic异常记录
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • #{}和${}的区别是什么 -- java面试
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (1)SpringCloud 整合Python
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (libusb) usb口自动刷新
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (windows2012共享文件夹和防火墙设置
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (四) Graphivz 颜色选择
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .net 流——流的类型体系简单介绍
  • .net 设置默认首页