关于Java 中的Optional的一些事

开始

定义一个实体类User,实现get、set方法

typescript 复制代码
public class User {
    String name;
    String sex;
    public User(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

定义一个UserRepository,用户仓库,实现仓库里面对数据库的user表进行username字段查询,假设user表里面有了"张三"这条数据,当查询到张三的时候,我们就会返回一"张三"对象,没有"张三"这条数据,就会返回null

typescript 复制代码
public class UserRepository {
    public User findUserByName(String name) {
        if (name.equals("张三")) {
            return new User("张三", "男");
        } else {
            return null;
        }
    }
}

再main函数中进行引用,实例化UserRepository对象,调用里的findUserByName方法,然后打印性别,当我们查询的"张三"的是时候,我们是假设了user表里面有一条张三,那么就会返回这个张三的数据,此时打印出的性别是"男"。

typescript 复制代码
public class Main {
    public static void main(String[] args) {
        UserRepository userRepository = new UserRepository();
        User user= userRepository.findUserByName("张三");
        System.out.println(user.getSex()); //男
    }
}

这个时候我们去查询"李四",就会出现报错;"NullPointerException" 因为表里面只有"张三"这条数据,没有李四,就会返回为null,然后,user.getSex()就会报错,都没有这个人,你还想知道他的性别。

typescript 复制代码
public class Main {
    public static void main(String[] args) {
        UserRepository userRepository = new UserRepository();
        User user= userRepository.findUserByName("李四");
        System.out.println(user.getSex());
    }
}

这个时候我们就需要加入if判断了,当有这个人,就是打印他的性别, 没有,就提示没有这个人。

csharp 复制代码
if (user != null) {
     System.out.println(user.getSex());
   } else {
      System.out.println("没有这个人");
     }

此时我么就避免了"NullPointerException"空指针异常的问题,那我们联想下,用户进行查数据的时候,他根本不知道里面有没有他想要的数据。当数据量很大的时候,都要去使用if去判断吗,这样会显的代码非常臃肿,增加了代码的阅读性,难以维护,此时Optioanl解决了我们的问题。

Optional

可以看做一个容器,里面可以包含任何东西,也可以什么都不包含, 对UserRepository的findUserByName方法进行修改,

vbnet 复制代码
public Optional<User> findUserByName(String name) {
        if (name.equals("张三")) {
            return Optional.of(new User("张三", "男"));
        } else {
            return Optional.empty();
        }
    }

ifPresent和ifPresentOrElse

再main中进行修改,使用Optional容器来包含User,ifPresent方法,如果optionalUser里面含值就会执行user -> System.out.println(user.getSex()),没有就不会执行,就会报错。

ini 复制代码
public static void main(String[] args) {
        UserRepository userRepository = new UserRepository();
        Optional<User> optionalUser= userRepository.findUserByName("李四");
        optionalUser.ifPresent(user -> System.out.println(user.getSex()));
    }

如果值为空的时候,我们想执行一些其他的操作。就需要用到ifPresentOrElse方法,有值就会执行第一个参数,没有值就会执行第二个参数。

less 复制代码
Optional<User> optionalUser= userRepository.findUserByName("李四");

optionalUser.ifPresentOrElse(
                user -> System.out.println(user.getSex()),
                () -> System.out.println("没有这个人"));
//没有这个人
    }

Optional的使用

Optional中的静态方法

of();

于创建一个包含指定值的Optional对象,使用of方法时必须要确定是有值的,

ini 复制代码
String txt = null;
Optional<String> optionalString  = Optional.of(txt);
//就会抛出NullPointerException,

ofNullable();

创建一个包含指定值的Optional对象可以有值也可以是空的,这个时候就不会出现异常了。

ini 复制代码
String txt = null;
Optional<String> optionalString  = Optional.ofNullable(txt);

empty();

创建一个空的Optional对象。

Optional中的实例方法

orElseThrow()

不带参数

ini 复制代码
String txt = null;
        Optional<String> optionalString  = Optional.ofNullable(txt);
        optionalString.orElseThrow();
//此时就会抛出一个异常:NoSuchElementException

带参数,自定义异常

vbnet 复制代码
String txt = null;
        Optional<String> optionalString  = Optional.ofNullable(txt);
        optionalString.orElseThrow(() ->
            new RuntimeException("Optional is null")
        );
// 抛出的异常为Optional is null

orElse()和orElseGet()方法

直接看代码,让你更好的理解

arduino 复制代码
public static void main(String[] args) {
        String txt = "zhangsan";
        Optional<String> optionalString  = Optional.ofNullable(txt);
        txt = optionalString.orElse(printf());
        System.out.println("txt的值是:" + txt);

        String txt1 = optionalString.orElseGet(() -> printf());
        System.out.println("txt1的值是:" + txt1);
    }

    public static String printf() {
        System.out.println("执行了printf方法");
        return "liSi";
    }
//打印结果:
//执行了printf方法
//txt的值是:zhangsan
//txt1的值是:zhangsan

此时我们可以看到: Optional有值时,orElse会执行,而orElseGet不会执行。 既然执行了orElse方法,并且我们返回的是"liSi",为什么打印变量txt值时候又是打印的"zhangSan",不是"liSi"我们可以看源码:

typescript 复制代码
public T orElse(T other) {
        return value != null ? value : other;
    }

其实里面的注释也说的很清楚了:If a value is present, returns the value, otherwise returns other. 存在这个值,就返回这个值,不存在,就返回其他。

现在我看下没有值的情况下是怎么样的:

typescript 复制代码
public static void main(String[] args) {
        String txt = null;
        Optional<String> optionalString  = Optional.ofNullable(txt);
        txt = optionalString.orElse(printf());
        System.out.println("txt的值是:" + txt);

        String txt1 = optionalString.orElseGet(() -> printf());
        System.out.println("txt1的值是:" + txt1);
    }

    public static String printf() {
        System.out.println("执行了printf方法");
        return "liSi";
    }
//打印结果:
执行了printf方法
txt的值是:liSi
执行了printf方法
txt1的值是:liSi

可以看到: Optional值为null的时候,orElse会执行,orElseGet也会执行。

我们再看下orElseGet源码

typescript 复制代码
public T orElseGet(Supplier<? extends T> supplier) {
        return value != null ? value : supplier.get();
    }

注释:If a value is present, returns the value, otherwise returns the result produced by the supplying function. 存在值,则返回该值,否则返回提供函数产生的结果。

总结

说白了就是传值就用orElse,需要调用方法获取就用orElseGet, Optional有没有值的时候都会调用orElse,而orElseGet只有Optional没有值的时候才会被调用。

相关推荐
Thinker QAQ12 分钟前
并发编程(十一):Shared Memory 与 Message Passing——关系与组合使用
java·python·go·并发编程·shared memory·message passing
齐 飞37 分钟前
idea中git误操作撤回git reset --hard ‘HEAD@{1}‘
java·git·intellij-idea
你的保护色1 小时前
多AS互联BGP4综合实验设计
java
OpsEye1 小时前
怎么实现大模型的按用户、按应用配额限流?
javascript·ai编程
某不知名網友1 小时前
ROS2进阶:服务通信、自定义SRV接口、参数服务器与基于服务的参数通信详解
java·开发语言·microsoft
Wang's Blog1 小时前
Java 项目实战: 交友项目 - MongoDB 入门:体系结构和命令行操作
java·mongodb·交友
小溪学编程1 小时前
将 Bean 放入 Spring 容器中的方式有哪些?
java·后端·spring
java_nnnn1 小时前
LeetCode刷题滑动窗口(水果成篮+找到字符串中所有字母的异位词)Java
java·开发语言·leetcode
用户3721574261352 小时前
Java 读取、修改和清空 PDF 文档属性(元数据)
java
SL_staff2 小时前
从‘改一行代码等三天’到‘改完即生效’:实施工程师的逻辑引擎避坑手记
java·产品·全栈