Optional类中的orElse和orElseGet的区别

本文详细对比了Java中Optional类的orElse与orElseGet方法的使用差异,特别是在Optional对象不为null,而参数为有返回值的函数时的情况。通过具体示例,解释了两种方法在函数执行上的区别。

  1. orElse方法与orElseGet方法对比表

Optional内对象参数效果注释
null对象相同

orElse和orElseGet方法都会返回参数对象

不为null对象相同返回Optional内对象
null有返回值的函数相同orElse和orElseGet方法都会返回参数内函数返回值
不为null有返回值的函数不同返回Optional内对象,但orElseGet不会执行函数内容,orElse会执行函数内容

2. 简单示例(仅针对orElse与orElseGet方法不同的情况,即Optional内对象不为null,且参数为有返回值函数)

 2.1 准备类

public class Staff {
        String name;
        Integer age;
        ... // getter setter
}

2.2 orElse 和 orElseGet的对比

    @Test
    void optionalTest(){

        Staff staff = new Staff("Jerome",12);

        System.out.println("----------------------orElseGet---------------------------");
        staffName = Optional.ofNullable(staff).map(s -> s.getName()).orElseGet(this::getName);
        System.out.println(staffName);

        System.out.println("----------------------orElse---------------------------");
        staffName = Optional.ofNullable(staff).map(s -> s.getName()).orElse( getName());
        System.out.println(staffName);
    }

    private String getName(){
        System.out.println("Get String if null");
        return "Get String";
    }

显示效果

----------------------orElseGet---------------------------
Jerome
----------------------orElse---------------------------
Get String if null
Jerome

<think>我们正在讨论JavaOptional的`orElse``orElseGet`方法。这两个方法都是在Optional对象为空时提供备选值,但它们在行为上有重要区别。 ### 1. **方法定义** - **`orElse(T other)`** 直接接受一个型为`T`的值作为参数。 ```java public T orElse(T other) { return value != null ? value : other; } ``` - **`orElseGet(Supplier<? extends T> other)`** 接受一个`Supplier`函数式接口,该接口在需要时才会被调用以生成备选值。 ```java public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } ``` ### 2. **核心区别:惰性求值** | 方法 | 参数型 | 求值时机 | 空值性能影响 | |--------------|----------------|------------------------------|-------------------| | `orElse` | 具体值 (`T`) | **立即求值**:无论Optional是否为空,参数表达式都会执行 | 可能产生不必要的计算开销 | | `orElseGet` | 函数 (`Supplier`) | **惰性求值**:仅当Optional为空时才执行函数 | 避免不必要的计算 | ### 3. **示例对比** 假设有一个需要远程调用的方法(耗时操作): ```java String fetchDefault() { System.out.println("调用远程服务获取默认值..."); return "default"; } ``` #### 场景1:Optional**非空**时 ```java Optional<String> opt = Optional.of("实际值"); // orElse: 即使有值也会执行fetchDefault() String result1 = opt.orElse(fetchDefault()); // 输出"调用远程服务..." // orElseGet: 有值时不会执行Supplier String result2 = opt.orElseGet(() -> fetchDefault()); // 无输出 ``` #### 场景2:Optional**为空**时 ```java Optional<String> opt = Optional.empty(); // 两者都会执行函数获取默认值 String result1 = opt.orElse(fetchDefault()); // 输出"调用远程服务..." String result2 = opt.orElseGet(() -> fetchDefault()); // 输出"调用远程服务..." ``` ### 4. **性能影响分析** $$ \text{时间开销} = \begin{cases} \text{orElse: } T_{\text{备选值计算}} & \text{无论是否为空} \\ \text{orElseGet: } \begin{cases} 0 & \text{非空时} \\ T_{\text{备选值计算}} & \text{为空时} \end{cases} \end{cases} $$ 当备选值的生成需要较高成本时(如数据库查询、网络请求、复杂计算): - ✅ **优先选择`orElseGet`**:避免不必要的资源消耗 - ⚠️ **`orElse`适用场景**:备选值是简单常量(如`"N/A"`、数字0等) ### 5. **设计思想** - **`orElse`**:适用于**已经存在**的简单对象(如常量、已计算的变量) - **`orElseGet`**:适用于需要**延迟生成**的复杂对象(通过函数动态创建) ### 6. **典型使用场景** | 场景 | 推荐方法 | 原因 | |-------------------------------|---------------|----------------------------------------------------------------------| | 返回缓存常量 | `orElse` | 常量已存在,无需额外计算 | | 执行数据库查询 | `orElseGet` | 避免无意义的数据库访问 | | 调用高开销服务 | `orElseGet` | 仅在必要时触发远程调用 | | 创建新对象 | `orElseGet` | 避免创建未被使用的对象(减少GC压力) | | 返回集合默认值 | `orElseGet` | 使用`Collections::emptyList`避免创建空集合实例 | ### 7. **错误使用示例** ```java // 反例:用orElse处理高开销操作 value.orElse(createExpensiveObject()); // 每次都会创建对象 // 正例:改用orElseGet value.orElseGet(() -> createExpensiveObject()); ``` --- ### 相关问题 1. Java 8的`Optional.orElseThrow()`方法在异常处理中的最佳实践是什么? 2. 如何利用`Optional.flatMap()`避免多层嵌套null检查? 3. 在Spring Data JPA中,`Optional`如何与Repository查询结果结合使用? 4. 为什么说滥用`Optional`可能导致性能下降?有哪些典型陷阱? 5. `Optional`与Kotlin的可空型(`?`)在设计哲学上有何异同?</think>### Java中`Optional.orElse()`与`orElseGet()`详解 #### 一、核心功能对比 | 方法 | 参数型 | 执行时机 | 空值处理策略 | |---------------|---------------|--------------------------|---------------------| | `orElse()` | 具体对象 `T` | **立即执行**:无论Optional是否为空,参数表达式都会计算 | 返回备用对象 | | `orElseGet()` | 函数式接口 `Supplier<T>` | **惰性执行**:仅当Optional为空时才触发函数计算 | 通过函数生成备用对象 | #### 二、方法定义解析 ```java // orElse: 直接返回备用对象 public T orElse(T other) { return value != null ? value : other; } // orElseGet: 通过Supplier函数生成对象 public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } ``` #### 三、关键区别:**执行时机** 假设有高开销方法: ```java String createExpensiveObject() { System.out.println("执行高开销操作..."); return "default"; } ``` ##### 场景1:Optional**非空**时 ```java Optional<String> opt = Optional.of("actualValue"); // orElse: 即使有值也会执行createExpensiveObject() String result1 = opt.orElse(createExpensiveObject()); // 输出:"执行高开销操作..." // orElseGet: 有值时不会执行Supplier String result2 = opt.orElseGet(() -> createExpensiveObject()); // 无输出 ``` ##### 场景2:Optional**为空**时 ```java Optional<String> opt = Optional.empty(); // 两者都会执行函数 opt.orElse(createExpensiveObject()); // 输出 opt.orElseGet(() -> createExpensiveObject()); // 输出 ``` #### 四、性能影响数学表示 $$ \text{时间开销} = \begin{cases} \text{orElse: } T_{\text{计算}} & \text{无论是否为空} \\ \text{orElseGet: } \begin{cases} 0 & \text{非空时} \\ T_{\text{计算}} & \text{为空时} \end{cases} \end{cases} $$ #### 五、最佳实践场景 | 场景 | 推荐方法 | 原因 | 示例 | |-------------------------------|---------------|--------------------------|--------------------------| | 返回简单常量 | `orElse` | 无额外开销 | `.orElse("N/A")` | | 执行数据库查询 | `orElseGet` | 避免无效查询 | `.orElseGet(() -> dao.findDefault())` | | 创建高开销对象 | `orElseGet` | 避免不必要的对象创建 | `.orElseGet(ArrayList::new)` | | 调用远程服务 | `orElseGet` | 防止无效网络请求 | `.orElseGet(() -> api.getDefault())` | #### 六、错误用法示例 ```java // 反例:orElse中直接调用高开销方法 value.orElse(createExpensiveObject()); // 每次都会执行 // 正例:orElseGet延迟执行 value.orElseGet(() -> createExpensiveObject()); ``` #### 七、设计思想 - **`orElse()`**:适用于**已存在**的简单对象(如常量、预计算值) - **`orElseGet()`**:适用于需要**动态生成**的复杂对象(通过函数延迟创建) > 经验法则:当备用值生成成本较高时,**始终选择`orElseGet`**;当备用值是简单常量时,两者性能无差异[^1][^2][^3][^4]。 --- ### 相关问题 1. 如何在`Optional.flatMap()`中正确处理嵌套空值? 2. `Optional.orElseThrow()`与传统`throw new Exception()`的性能对比如何? 3. 为什么说在Entity中使用`Optional`字段可能违反设计规范? 4. Java 9的`Optional.ifPresentOrElse()`方法解决了什么痛点? 5. 在Stream API中结合`Optional`有哪些高效的空值处理模式?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值