关于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没有值的时候才会被调用。

相关推荐
游荡de蝌蚪8 分钟前
快速打造Vue后台管理系统
前端·javascript·vue.js
June_liu2 小时前
列太多vxe-table自动启用横向虚拟滚动引起的bug
前端·javascript
云枫晖2 小时前
手写Promise-then的基础实现
前端·javascript
养生达人_zzzz2 小时前
飞书三方登录功能实现与行业思考
前端·javascript·架构
GarrettGao2 小时前
Frida常见用法
javascript·python·逆向
肥晨2 小时前
前端私有化变量还只会加前缀嘛?保姆级教程教你4种私有化变量方法
前端·javascript
小高0072 小时前
前端 Class 不是花架子!3 个大厂常用场景,告诉你它有多实用
前端·javascript·面试
间彧2 小时前
Spring Boot项目中如何实现Redis分布式锁
java
掘金安东尼2 小时前
AI 应用落地谈起 ,免费试用 Amazon Bedrock 的最佳时机
java·架构
杨杨杨大侠3 小时前
案例03-附件E-部署运维
java·docker·github