Optional的使用

一、Optional概述

Optional是Java 8中新增的一个类,用于解决空指针异常(NullPointerException)问题。Optional类包装了一个对象,并提供了一组方法来处理该对象是否为空的情况,避免了在代码中频繁使用null值的情况。
理解关键: 可以把Optional理解成容器,把对象包裹进Optional容器中进行一系列的判空、映射等操作

二、Optional的用法介绍

1. 构建类方法

Optional.of(T t) : 创建一个 Optional 实例,t 必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):t 可以为 null

源码解析
of和ofNullable
两者都是获取Option实例,并且都是静态的
of 会抛出空指针异常

// 把实例放入Optional容器
public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

// 放入Optional容器时进行判空
private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

// 为空的情况下抛出空指针异常
public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

ofNullable 进行了判空处理

// 区别与of:为空的情况下返回空的Optional容器
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

验证示例:

@Test
public void of_test() {
    User user = null;
    Optional<User> optional = Optional.of(user);
    System.out.println(user);
}

@Test
public void ofNullable_test() {
    User user = null;
    Optional<User> optional = Optional.ofNullable(user);
    System.out.println(user);
}

2. 获取类方法

T get(): 如果调用对象包含值不为 null,返回该值,否则抛异常
T orElse(T other) :如果有值则将其返回,否则返回指定的 other 对象。
T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由 Supplier 接口实现提供的对象。
T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由 Supplier

源码解析

// 如果值存在,则取出该值,否则抛出异常NoSuchElementException
public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

// 如果值存在,则取出该值,否则返回缺省值other
public T orElse(T other) {
    return value != null ? value : other;
}

// 如果值存在,则取出该值,否则返回由供应函数supplier产生的结果
public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

// 如果值存在,则取出该值,否则返回由供应函数supplier产生的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

验证示例

@Test
public void orElseGet_test() throws Throwable {
    final Optional<String> optional = Optional.ofNullable("2");
    System.out.println(optional.get());
    System.out.println(optional.orElse("0"));
    System.out.println(optional.orElseGet(() -> "0"));
    System.out.println(optional.orElseThrow(NullPointerException::new));
}

3. 判断类方法

boolean isPresent() : 判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它。 

源码解析

// 判断值是否存在,返回布尔值
public boolean isPresent() {
    return value != null;
}

// 如果存在值,则使用该值执行给定的操作,否则不执行任何操作。
public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

验证示例

@Test
public void  presentTest(){
    final Optional<String> optional = Optional.ofNullable("2");
    System.out.println(optional.isPresent());
    optional.ifPresent(System.out::println);
}

4. 过滤类方法

Optional<T> filter(Predicate<? super <T> predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional

源码解析

// 如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。
public Optional<T> filter(Predicate<? super T> predicate) {
    // 入参预测函数校验
    Objects.requireNonNull(predicate);
    // 不存在值直接返回this,也就是当前Optional实例
    if (!isPresent())
        return this;
    else
    // 值存在,并且匹配预测,返回满足预测的Optional,否则返回空的Optional
        return predicate.test(value) ? this : empty();
}

验证示例

@Test
public void filterTest() {
    final Optional<Integer> optional = Optional.ofNullable(2);
    System.out.println(optional.filter(e -> e > 1).get());
}

5. 映射类方法

<U>Optional<U> map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返回一个空的 Optional 对象

map和flatMap
相同点: 两个方法的返回值都是 Optional 对象!
不同点: 区别在于调用两个方法需要的传入参数(函数式接口)的返回值不同,
map 方法会自动将入参中的函数式接口返回值包装成 Optional 对象,而 flatMap 方法则要求入参中的函数式接口返回值本身就是 Optional 对象。

方法	map	flatMap
方法签名	public Optional map(Function<? super T, ? extends U> mapper)	public Optional flatMap(Function<? super T, Optional> mapper)
函数式接口入参	T或的T的子类实例	T或的T的子类实例
函数式接口返回值	U(任意对象)	Optional对象
方法返回值	将入参中的函数式接口返回值包装成 Optional	就是入参中的函数式接口返回值

 @Test
 public void map_test() {
     User user = User.builder().userName("小四").build();
     final Optional<String> optional = Optional.ofNullable(user).map(User::getUserName);
     final Optional<String> optional1 = Optional.ofNullable(user).flatMap(user1 -> Optional.ofNullable(user1.getUserName()));
     System.out.println(optional.get());
     System.out.println(optional1.get());
 }

三、使用场景

1. 使用Optional优化多层调用

public class Person {
    private String name;
    private Optional<Company> company;
    // ...
}

public class Company {
    private String name;
    private Optional<Address> address;
    // ...
}

public class Address {
    private String city;
    // ...
}

// 多层调用
Person person = new Person();
if (person != null) {
    Company company = person.getCompany();
    if (company != null) {
        Address address = company.getAddress();
        if (address != null) {
            String city = address.getCity();
            if (city != null) {
                System.out.println(city);
            }
        }
    }
}

// 使用Optional优化多层调用
String city = Optional.ofNullable(person)
        .flatMap(Person::getCompany)
        .flatMap(Company::getAddress)
        .map(Address::getCity)
        .orElse("unknown");
System.out.println(city);

2. 值非空情况下执行特定逻辑

// 传统写法
String str = null;
if (str != null) {
    System.out.println(str.toUpperCase());
}

// 使用Optional优化
Optional<String> optional = Optional.ofNullable(str).ifPresent(s -> System.out.println(s.toUpperCase()));

3. 简化try-catch语句

// 传统写法
String content = "";
File file = new File("filename.txt");
try (Scanner scanner = new Scanner(file)) {
    content = scanner.useDelimiter("\\Z").next();
} catch (IOException e) {
    e.printStackTrace();
}

// 使用Optional优化
File file = new File("filename.txt");
Optional<String> optional = Optional.empty();
try {
    optional = Optional.of(new Scanner(file).useDelimiter("\\Z").next());
} catch (IOException e) {
    e.printStackTrace();
}
String content = optional.orElse("");


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值