Java中Optional的orElse操作及orElse与orElseGet的区别详解

 更新时间:2025年05月02日 09:15:58   作者:小学鸡!  
Optional中orElse可能导致空指针异常,orElseGet可以避免这种情况,这篇文章主要介绍了Java中Optional的orElse操作及orElse与orElseGet区别的相关资料,文中给出了详细的代码示例,需要的朋友可以参考下

1. 大概说明

这篇文章的目的是为了说明:

  • orElse 如何使用
  • orElseGet 如何使用
  • 两者的区别

备注:orElse 可能导致 NullPointerException,当 orElse 的参数是间接计算得来的时候。虽然这种说法有点牵强(因为并不是orElse导致了空指针异常),但是使用 orElseGet 确实可以避免这种情况。

2. 详细分析

2.1 .orElse 操作

先看个例子:

Optional<String> optional = Optional.empty();
System.out.println(optional.isPresent); // ---->输出:false
// 返回 false,表示 Optional 里没有值。

解析:

  • Optional.empty() 代表 一个空的 Optional 实例,即 Optional 没有值
  • Optional.ofNullable(null) 等价于 Optional.empty()

2.2 .orElse 的作用:避免空指针异常

  • 如果 Optional 为空(即 Optional.empty()),就返回 orElse() 里提供的默认值。
  • 如果 Optional 有值,就直接返回这个值,不执行 orElse() 提供的默认值。

注意:不管 Optional 为不为空,这个值都会创建,只不过为空时,才使用

// 举例:当Optional为空时,orElse()才会触发
String result = Optional.ofNullable(null)
    .orElse("默认值");
System.out.println(result); // ---->输出:默认值
// 再举个例子:
Map<Long, List<String>> map = new HashMap<>();
map.put(1L, Arrays.asList("A", "B", "C"));

List<String> result = Optional.ofNullable(map.get(1L))
    .orElse(Collections.emptyList()); // 为null就返回 空列表
System.out.println(result);  // ---->输出:[A, B, C] (orElse() 没起作用)

2.3 为什么要用?

List<String> result = Optional.ofNullable(map.get(0L))
    .orElse(Collections.emptyList())
    .stream();

如果 map.get(0L) == null,那么:

  • 不加 .orElse(Collections.emptyList()) → .stream() 会报 NullPointerException ❌
  • 加了 .orElse(Collections.emptyList()) → .stream() 能正常执行 ✅

2.4 orElseGet如何使用

再来看看 orElseGet 中如何使用:

orElseGet 作用:获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据;如果为空则返回传入的参数来创建对象。

具体的使用案例可看下图:

2.5 orElse和orElseGet的区别

orElse() 和 orElseGet() 都是Optional 类中的方法,用于在 Optional 为空时提供默认值。但它们的区别在于 默认值的获取方式

1、orElse(T other)

  • 直接传递一个默认值
  • 即使 Optional里有值,也会创建 other 对象,但不会使用它
  • 适用于默认值创建代价较低的情况

2、orElseGet(Supplier<? extends T> supplier)

  • 传递的是一个 Supplier(懒加载:只有需要的时候才会创建)接口,它是一个函数式接口,形式是这样的:()->{ return computedResult },即入参为空,有返回值(任意类型的)
  • 仅当 Optional 为空时才会执行 supplier.get(),不会提前创建默认值
  • 适用于默认值创建代价较高的情况

看个例子:

class User {
    // 中文名
	private String chineseName;
	// 英文名
	private EnglishName englishName;
}

class EnglishName {
    // 全名
    private String fullName;
    // 简写
    private String shortName;
}

假如我们现在有 User 类,用户注册账号时,需要提供自己的中文名或英文名,或都提供,我们抽象出一个EnglishName 类,它包含英文名的全名和简写(因为有的英文名确实太长了)。现在,我们希望有一个User.getName() 方法,它可以像下面这样实现:

class User {
    // ... 之前的内容
    public String getName1() {
        return Optional.ofNullable(chineseName)
                .orElse(englishName.getShortName());
    }
    
    public String getName2() {
        return Optional.ofNullable(chineseName)
                .orElseGet(() -> englishName.getShortName());
    }
}

写了两个版本,分别使用 orElse 和 orElseGet。现在,你可以看出 getName1() 方法有什么风险了吗?它会出现空指针异常吗?----> 是的。当用户只提供了中文名时,此时 englishName 属性是 null,但是在 orElse 中,englishName.getShortName()总是会执行。而在 getName2() 中,这个风险却没有。

再举个例子:

public class Test {
    public static void main(String[] args) {
        System.out.println("orElse() 的情况:");
        String result1 = Optional.ofNullable("实际值")
            .orElse(test2());
        System.out.println("最终结果: " + result1);

        System.out.println("orElseGet() 的情况:");
        String result2 = Optional.ofNullable("实际值")
            .orElseGet(() -> test2());
        System.out.println("最终结果: " + result2);
    }

    public static String test2() {
        System.out.println("执行昂贵的计算...");
        return "昂贵默认值";
    }
}

输出:

orElse() 的情况:
执行昂贵的计算...
最终结果: 实际值

orElseGet() 的情况:
最终结果: 实际值

总结

到此这篇关于Java中Optional的orElse操作及orElse与orElseGet区别详解的文章就介绍到这了,更多相关Java Optional的orElse操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • 详解Java I/O流中的字符流有哪些

    详解Java I/O流中的字符流有哪些

    字节流的功能已经十分强大,几乎可以直接或间接地处理任何类型的输入/输出操作,但它却不能直接操作16位的Unicode字符,这就需要使用字符流,所以在今天的内容中,小编会给大家讲解IO流中的字符流,希望各位能够继续耐心学习
    2023-10-10
  • eclipse springboot工程打war包方法及再Tomcat中运行的方法

    eclipse springboot工程打war包方法及再Tomcat中运行的方法

    这篇文章主要介绍了eclipse springboot工程打war包方法及再Tomcat中运行的方法,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • SpringBoot+aop实现主从数据库的读写分离操作

    SpringBoot+aop实现主从数据库的读写分离操作

    读写分离的作用是为了缓解写库,也就是主库的压力,但一定要基于数据一致性的原则,就是保证主从库之间的数据一定要一致,这篇文章给大家介绍SpringBoot+aop实现主从数据库的读写分离操作,感兴趣的朋友跟随小编一起看看吧
    2024-03-03
  • Java多线程之中断线程(Interrupt)的使用详解

    Java多线程之中断线程(Interrupt)的使用详解

    interrupt字面上是中断的意思,但在Java里Thread.interrupt()方法实际上通过某种方式通知线程,并不会直接中止该线程
    2013-05-05
  • SpringBoot Java后端实现okhttp3超时设置的方法实例

    SpringBoot Java后端实现okhttp3超时设置的方法实例

    Okhttp的使用没有httpClient广泛,网上关于Okhttp设置代理的方法很少,下面这篇文章主要给大家介绍了关于SpringBoot Java后端实现okhttp3超时设置的相关资料,需要的朋友可以参考下
    2021-10-10
  • 一篇文章带你深入了解Java类加载

    一篇文章带你深入了解Java类加载

    这篇文章主要介绍了Java中类加载过程全面解析,具有一定参考价值,需要的朋友可以了解下,希望能给你带来帮助
    2021-08-08
  • MyBatisPlus条件构造器的实现示例

    MyBatisPlus条件构造器的实现示例

    本文主要介绍了MyBatisPlus条件构造器的实现示例,主要包括了QueryWrapper,UpdateWrapper,LambdaQueryWrapper,LambdaUpdateWrapper这四种,具有一定的参考价值,感兴趣的可以了解下
    2023-12-12
  • java小程序火锅店点餐系统

    java小程序火锅店点餐系统

    这篇文章主要介绍了java小程序火锅店点餐系统,采用Java语言和Vue技术,以小程序模式实现的火锅点菜系统,文中提供了解决思路和部分实现代码,需要的朋友可以参考下
    2023-03-03
  • 浅析Java数据库操作工具包jOOQ的使用

    浅析Java数据库操作工具包jOOQ的使用

    jOOQ 是一个轻量级的 Java ORM(对象关系映射)框架,可用来构建复杂的 SQL 查询,这篇文章主要来和大家介绍一下jOOQ的使用,需要的可以参考下
    2024-04-04
  • java实现小猫钓鱼游戏

    java实现小猫钓鱼游戏

    这篇文章主要为大家详细介绍了java实现小猫钓鱼游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01

最新评论