Optional 是个好东西,你真的会用嘛?

最近在项目中,看到一段很优雅的代码,用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的过程中呢,有些时候,会使用到isPresentifPresent,他们有点像,一个就是判断value值是否为空,另外一个就是判断value值是否为空再去做一些操作。比如ifPresent:

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);
});

优雅永不过时,嘻嘻~

在使用 `vi` 编辑器时,如果进入编辑模式后出现异常字符,并且删除键无法正常工作,通常是由于终端设置不正确或某些配置文件中设置了非标准的键盘映射。以下是详细分析和解决方法: ### 1. 确认是否处于正确的编辑模式 在 `vi` 中,有三种主要模式: - **命令模式(Normal Mode)**:刚打开文件时默认进入的模式,用于执行命令如移动光标、复制、粘贴等。 - **插入模式(Insert Mode)**:通过按 `i`、`a`、`o` 等命令进入,在此模式下可以输入文本。 - **可视模式(Visual Mode)**:用于选择文本块。 如果你在插入模式下遇到异常字符,可能是终端模拟器与 `vi` 的输入处理机制不一致导致的。确保你按下的是 `i` 键进入插入模式,并看到屏幕下方显示“-- INSERT --”提示[^4]。 ### 2. 检查终端类型设置 `vi` 和 `vim` 依赖于环境变量 `TERM` 来识别终端的功能。如果该变量未正确设置,可能导致键盘输入异常。可以通过以下命令查看当前终端类型: ```bash echo $TERM ``` 常见值包括 `xterm`、`xterm-256color`、`linux` 等。如果值为空或不正确,可以在 `.bashrc` 或 `.profile` 文件中添加如下内容: ```bash export TERM=xterm-256color ``` 然后重新加载配置文件: ```bash source ~/.bashrc ``` ### 3. 使用 `stty` 命令检查终端行为 有时终端的原始模式被修改,导致退格键等行为异常。可以尝试运行以下命令重置: ```bash stty sane ``` 这将恢复终端的默认设置,通常能解决按键响应问题[^1]。 ### 4. 配置 `.vimrc` 文件(适用于 `vim`) 如果你使用的是 `vim` 而不是原始的 `vi`,可以在用户目录下创建或修改 `.vimrc` 文件,添加以下内容以确保兼容性和正常的键盘行为: ```vim set nocompatible set backspace=indent,eol,start ``` 第一行禁用 Vi 兼容模式,第二行允许退格键删除自动缩进、换行符和插入模式开始前的字符[^2]。 ### 5. 安装完整版 `vim` 某些系统默认安装的是简化版 `vi`,功能受限。建议安装完整的 `vim`: ```bash sudo apt update && sudo apt install vim ``` 安装完成后使用 `vim` 替代 `vi` 运行,通常会有更好的用户体验和支持更多的功能。 ### 6. 使用 `infocmp` 检查终端描述 如果上述方法无效,可能是终端描述文件损坏或缺失。可以使用 `infocmp` 工具检查当前终端类型的描述信息: ```bash infocmp ``` 如果输出为空或错误,可以尝试重新生成或安装相应的 terminfo 数据库: ```bash sudo apt install ncurses-term ``` ### 示例:修复 `.vimrc` 配置 ```vim " Disable vi-compatible mode set nocompatible " Enable proper backspace behavior set backspace=indent,eol,start " Use syntax highlighting (optional but recommended) syntax on " Show line numbers (optional) set number ``` 保存并退出后,重新启动 `vim` 查看效果。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值