原来 Optional 用起来这么清爽!

举报
yd_244540595 发表于 2024/08/07 16:50:53 2024/08/07
【摘要】 前言大家好,我是捡田螺的小男孩。最近在项目中,看到一段很优雅的代码,用 Optional 来判空的。我贴出来给大家看看://遍历打印 userInfoListfor (UserInfo userInfo : Optional.ofNullable(userInfoList).orElse(new ArrayList<>())) { //print userInfo}这段代码因为 Opt...

前言

大家好,我是捡田螺的小男孩

最近在项目中,看到一段很优雅的代码,用 Optional 来判空的。我贴出来给大家看看:

//遍历打印 userInfoList
for (UserInfo userInfo : Optional.ofNullable(userInfoList)
.orElse(new ArrayList<>())) {
    //print userInfo
}

这段代码因为 Optional 的存在,优雅了很多,因为 userInfoList 可能为 null,我们通常的做法,是先判断不为空,再遍历:

if (!CollectionUtils.isEmpty(userInfoList)) {
    for (UserInfo userInfo:userInfoList) {
      //print userInfo
    }
  }
 

显然,Optional 让我们的判空更加优雅啦、

1. 没有 Optional,传统的判空?

如果只有上面这一个例子的话,大家会不会觉得有点意犹未尽呀。那行,田螺哥再来一个。

假设有一个订单信息类,它有个地址属性。

要获取订单地址的城市,会有这样的代码:

String city = orderInfo.getAddress().getCity();
 

这块代码会有啥问题呢?是的,可能报空指针问题!为了解决空指针问题,一般我们可以这样处理:

if (orderInfo != null) {
    Address address = orderInfo.getAddress();
    if (address != null) {
        String city = address.getCity();
    }
}

这种写法显然有点丑陋。为了更加优雅一点,我们可以使用 Optional

     String city = Optional.ofNullable(orderInfo)
                .map(Order::getAddress)
                .map(Address::getCity)
                .orElseThrow(() ->
                new IllegalStateException("OrderInfo or Address is null"));

这样是不是优雅一点,好了这例子也介绍完了。

有些伙伴,可能第一眼看那个 Optional 优化后的代码有点生疏。因此,接下来,给介绍 Optional 相关 API

2. Optional API 简介

2.1 ofNullable(T value)、empty()、of(T value)

因为我们上面的例子,使用到了 Optional.ofNullable(T value),第一个函数就讲它啦。源码如下:

  public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
 

如果 value 为 null,就返回 empty(),否则返回 of(value) 函数。接下来,我们看 Optional 的 empty()  of(value) 函数

public final class Optional<T> {

  private static final Optional<?> EMPTY =  new Optional<>();
    
  public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

显然, empty()函数的作用就是返回 EMPTY 对象。

 of(value) 函数会返回 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;
}
 
  • 当 value 值为空时,会报 NullPointerException
  • 当 value 值不为空时,能正常构造 Optional 对象。

2.2 orElseThrow(Supplier<? extends X> exceptionSupplier)、orElse(T other) 、orElseGet(Supplier<? extends T> other)

上面的例子,我们用到了 orElseThrow

 .orElseThrow(() -> new IllegalStateException("OrderInfo or Address is null"));

那我们先来介绍一下它吧:

public final class Optional<T> {

  private final T value;
    
  public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
 }

很简单就是,如果 value 不为 null,就返回 value,否则,抛出函数式 exceptionSupplier 的异常。

一般情况,跟 orElseThrow 函数功能相似的还有 orElse(T other)  orElseGet(Supplier<? extends T> other)

public T orElse(T other) {
    return value != null ? value : other;
}
 

对于 orElse,如果 value 不为 null,就返回 value ,否则返回 other

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}
 

对于 orElseGet,如果 value 不为 null,就返回 value ,否则返回执行函数式 other 后的结果。

2.3 map 和 flatMap

我们上面的例子,使用到了 map(Function<? super T, ? extends U> mapper)

Optional.ofNullable(orderInfo)
                .map(Order::getAddress)
                .map(Address::getCity)
 

我们先来介绍一下它的:

  public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }

   public boolean isPresent() {
        return value != null;
    }
 

其实这段源码很简答,先是做个空值检查,接着就是 value 的存在性检查,最后就是应用函数并返回新的 Optional```

.map 相似的,还有个 flatMap,如下:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
 

可以发现,它两差别并不是很大,主要就是体现在入参所接受类型不一样。

2.4 isPresent 和 ifPresent

我们在使用 Optional 的过程中呢,有些时候,会使用到 isPresent  ifPresent,他们有点像,一个就是判断 value 值是否为空,��外一个就是判断 value 值是否为空,再去做一些操作。比如:

public void ifPresent(Consumer<? super T> consumer) {
  if (value != null)
    consumer.accept(value);
}

即判断 value 值是否为空,然后做一下函数式的操作。

举个例子,这段代码:

if(userInfo!=null){
    doBiz(userInfo);
}
 

用了 isPresent 可以优化为:

 Optional.ofNullable(userInfo)
    .ifPresent(u->{
      doBiz(u);
});

优雅永不过时,嘻嘻~

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。