Java8 Optional的使用

本文深入讲解Java8中Optional类的使用方法,旨在帮助开发者有效避免空指针异常,提升代码质量和可读性。通过实例演示Optional如何简化判空操作,减少冗余代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Optional简介

Optional类是java8新增的类,主要是用来解决空指针异常(NullPointerException)。Optional类在函数式编程规范中具有重要意义。Optional方法可以避免频繁的判空操作。

例如:

public void function(User u){
    if(u!=null){
        Adder adder = u.getAdder();
        if(adder!=null){
            Area area = adder.getArea();
            if(area!=null){
                String name = area.getName();
                if(name!=null){
                    System.out.println(name.toUpperCase());
                }
            }
        }
    }
}

如果不这样一层层的判空,直接执行,则很有可能抛出空指针异常:

System.out.println(u.getAdder().getArea.getName().toUpperCase());

如果我们使用了Optional类,则很方便的排除了频繁的判空操作:

Optional op = Optional.ofNullable(u);
String name = op.map(User::getAdder)
                        .map(Adder::getArea)
                        .map(Area::getName)
                        .map(String::toUpperCase)
                        .orElse("");
 System.out.println(name);        

注意:

  • isPresent()方法与obj!=null并无区别
  • Optional类不应该用在类的属性和方法参数上(Optional类型不可被序列化)
  • 使用Optional应该使用此类提供的各种方法来判空,而不是直接使用isPresent()和get()方法,这样与平时的!=null并没有本质的优化和区别

Optional类使用

Optional类构造方式
  1. Optional.of(obj)
    传入的obj值不能为null值,否则抛出异常NullPointerException。
User user = new User("zhangsan",23);
Optional<User> op = Optional.of(user);
op.ifPresent(u->{ 
    //执行打印
    System.out.println(u.getName());
 });
  1. Optional.ofNullable(obj)
    传入的值不明确是否为null (obj可能为null,可能不为)。源代码是判断了obj是否为null来分别调用Optional.empty()和Optional.of(obj)方法来实现。
User user = null;
Optional<User> op = Optional.ofNullable(user);
op.ifPresent(u->{
    //不执行
    System.out.println(u.getName());
});
  1. Optional.empty()
    显示的创建一个空的Optional对象
Optional<User> op = Optional.empty();
op.ifPresent(u->{
    //不执行
    System.out.println(u.getName());
});
Optional类其他方法
  1. orElse(obj)
    存在则直接返回,不存在则返回提供的默认值;
User user1 = null;
User user2 = new User("lisi",24);
Optional<User> op = Optional.ofNullable(user1);
//如果op对象值为空则返回user2,否则返回原值
User user = op.orElse(user2);
System.out.println(user);
  1. orElseGet(Supplier<? extends T> other)
    存在则直接返回,不存在则由函数产生
User user1 = null;
Optional<User> op = Optional.ofNullable(user1);
//op有值则直接返回值,否则执行函数生成返回
User user = op.orElseGet(()-> new User("lisi",25));
System.out.println(user);

注意:如果代码

User user = op.orElse(createObj());
User user = op.orElseGet(createObj());

public User createObj(){
    return new User();
}

当op为empty时,都会执行createObj()方法。当op不为empty时,orElse还是会执行createObj()方法,造成内存开销。而orElseGet()则不会执行createObj()方法。

  1. orElseThrow(Supplier<? extends X> exceptionSupplier)
    放值存在时返回值,值不存在则抛出参数异常。
User lisi = op.orElseThrow(() -> new  NullPointerException());
System.out.println(lisi);
  1. ifPresent(Consumer<? super T> consumer)
    当值存在则执行函数式方法
User user = new User("zhangsan",23);
Optional<User> op = Optional.of(user);
op.ifPresent(u->{ 
    //执行打印
    System.out.println(u.getName());
 });

不要像以前那样的方式来使用:

if (op.isPresent()) {
  System.out.println(op.get());
}
  1. isPresent()
    判断对象值是否存在,返回boolean值
Optional<User> op = Optional.empty();
boolean flag = op.isPresent()
//打印false
System.out.println(flag);
  1. map()
    参数:Function<? super T, ? extends U> mapper
    返回值:Optional
    Optional对象的映射,可以级联返回Optional对象供连续调用。
    例如:需要获取user的姓名,并将姓名转换为大写打印,如果不存在则打印不存在

原始写法

//原始写法,不得不一层一层的执行判空操作
public void function(User user){
    if(user!=null){
        String name = user.getName();
        if(name!=null){
            System.out.println(name.toUpperCase());
        }else{
             System.out.println("不存在");
        }
    }else{
        System.out.println("不存在");
    }
}

Optional.map() 方法

//使用了map方法,级联的调用,精简代码
public void function(User user){
  String name = op.map(u -> u.getName())
                         .map(n -> n.toUpperCase())
                         .orElse("不存在");
   
   System.out.println(name);
}
  1. flatMap()
    flatMa()方法与map类似,不同的是,map的参数函数式方法返回的类型是Optional,而flatMap的参数函数式方法赶回的类型是拆包装值。
 public class User {
    private String name;
    private Integer age;
    private Integer sex;
    public Optional<Integer> getSex(){
        return Optional.ofNullable(sex);
    }
}
 
 //flatMap的参数返回值必须为Optional类型
Integer sex = op.flatMap(User::getSex).orElse(-1);
System.out.println(sex);
  1. filter()
    参数:Predicate<? super T> predicate
    返回值:Optional
    filter方式可以通过执行参数方法来过滤值,不通过则返回empty对象,通过则返回原对象。
Optional<User> op = Optional.of(new User("李四",20));
//使用filter过滤是否是张三,再用map映射返回
String s = op.filter(u -> u.getName().equals("张三"))
                 .map(User::getName)
                 .orElse("不存在");
//打印不存在
System.out.println(s);
<think>好的,我现在需要帮助用户了解Java 8Optional类的使用方法。首先,我得回忆一下Optional类的基本概念和设计目的。根据引用[2]和[4],Optional主要是为了避免空指针异常,通过包装可能为null的值,强制开发者显式处理可能为空的情况。 接下来,用户需要的是使用教程,所以我应该从创建Optional对象开始。引用[2]提到有几种创建方式:Optional.of、Optional.ofNullable和Optional.empty。这里需要注意,Optional.of如果传入null会抛出异常,而ofNullable允许参数为null,所以需要分情况说明。 然后,常用的方法有哪些呢?比如map、flatMap、orElse、orElseGet、orElseThrow等。引用[3]提到了map和flatMap的区别,map用于转换值,而flatMap用于处理返回Optional的方法,避免嵌套。比如用户有一个User对象,想获取name,可以用map(User::getName),但如果getName本身返回Optional,就需要用flatMap。 另外,错误处理很重要。比如orElse和orElseGet的区别在于,orElse无论是否为空都会执行参数中的表达式,而orElseGet只有在值为空时才执行Supplier函数。这可能会影响性能,需要指出。 用户可能还会问到如何正确使用Optional,避免常见的反模式,比如直接调用get()而不检查isPresent(),这样可能导致NoSuchElementException。应该推荐使用orElse等方法替代。 还要考虑实际应用场景,比如在流处理中结合使用Optional,或者作为方法返回类型,提醒调用者处理可能的空值。引用[4]中的例子展示了如何使用ofNullable和orElse来提供默认值,这可以作为示例说明。 需要检查是否有遗漏的方法,比如ifPresent,它接受Consumer接口,可以在值存在时执行操作。或者filter方法,用于基于条件过滤值。这些方法可以增强代码的简洁性和安全性。 最后,总结最佳实践,比如避免将Optional用作字段或方法参数,而是作为返回类型。同时,不要过度使用Optional,只在可能返回null的地方使用,以保持代码的清晰。 现在需要将这些内容组织成一个结构清晰的教程,分步骤讲解创建对象、常用方法、注意事项和示例代码。确保示例代码正确,比如使用Optional.ofNullable(user).map(User::getName).orElse("default")这样的链式调用,展示如何安全地处理可能为null的值。 同时,根据用户提供的引用,需要正确引用相关部分,比如创建对象的部分引用[2][4],map和flatMap引用[3],设计目的引用[2][4]等。确保引用标识符正确对应,并且自然融入回答中。 最后生成相关问题,可能需要包括Optional与空指针异常的关系、常用方法比较、最佳实践、与流的结合使用等,帮助用户进一步学习。</think>### Java 8 Optional使用教程 #### 一、Optional 类的设计目标 Optional 类是 Java 8 引入的包装类,**主要用于解决空指针异常问题**。通过明确表示值的存在与否,开发者能更安全地处理可能为 `null` 的情况[^2][^4]。 #### 二、创建 Optional 对象 1. **`Optional.of(value)`** 创建包含非空值的 Optional 对象,若 `value` 为 `null` 会抛出 `NullPointerException`[^2][^4]。 ```java Optional<String> stringOptional = Optional.of("Java"); ``` 2. **`Optional.ofNullable(value)`** 允许值为 `null`,适用于不确定值是否存在的场景。 ```java User user = null; Optional<User> userOptional = Optional.ofNullable(user); ``` 3. **`Optional.empty()`** 创建一个空的 Optional 对象。 ```java Optional<Object> emptyOptional = Optional.empty(); ``` --- #### 三、常用操作方法 1. **`isPresent()` 与 `ifPresent()`** - `isPresent()`:检查值是否存在。 - `ifPresent(Consumer)`:值存在时执行操作。 ```java userOptional.ifPresent(u -> System.out.println(u.getName())); ``` 2. **`orElse()` 与 `orElseGet()`** - `orElse(T defaultValue)`:直接返回默认值。 - `orElseGet(Supplier)`:延迟生成默认值(仅在需要时执行)[^4]。 ```java User defaultUser = userOptional.orElse(new User("Guest")); User lazyUser = userOptional.orElseGet(() -> createDefaultUser()); ``` 3. **`map()` 与 `flatMap()`** - `map(Function)`:转换值类型(如从 `User` 提取 `String` 名称)[^3]。 - `flatMap(Function)`:处理嵌套 Optional(如方法返回 `Optional<String>`)。 ```java Optional<String> name = userOptional.map(User::getName); Optional<String> nestedName = userOptional.flatMap(u -> u.getOptionalName()); ``` 4. **`filter()`** 基于条件过滤值: ```java Optional<User> adultUser = userOptional.filter(u -> u.getAge() >= 18); ``` --- #### 四、避免空指针的典型场景 1. **链式调用** 安全访问嵌套对象属性: ```java String city = Optional.ofNullable(user) .map(User::getAddress) .map(Address::getCity) .orElse("Unknown"); ``` 2. **结合 Stream API** 过滤空值并处理集合: ```java List<String> names = users.stream() .map(user -> Optional.ofNullable(user.getName())) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); ``` --- #### 五、注意事项 1. **不要滥用 Optional** - 避免将 Optional 作为类字段或方法参数[^4]。 - 优先用于方法返回值,而非替代所有 `null` 检查。 2. **避免直接调用 `get()`** 使用 `orElse()` 或 `orElseThrow()` 替代: ```java // 不推荐 if (userOptional.isPresent()) { User u = userOptional.get(); } // 推荐 User u = userOptional.orElseThrow(() -> new NoSuchElementException()); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值