Java8中Optional的正确使用姿势

单纯的使用Optional并不能很好的解决业务中的NPE问题 - 简书
https://www.jianshu.com/p/f21afe47a3e7

单纯的使用Optional并不能很好的解决业务中的NPE问题

工作中经常会遇到NPE(NullPointException)问题怎么处理,得到最多的回答就是Optional来处理,但是单纯的使用Optional并不能很好的解决业务中的NP问题。所以整理出日常工作中处理NPE问题的思路,供参考。

先看一下思路:

解决NPE的思路

01 错误的姿势

01.01 避免入参使用 Optional

原因: 

1. 干扰阅读者, 让方法的意图模糊

2. 别人在调用该方法时, 还需要专门new一个Optional后才能传进来, 显得调用繁琐

日常工作中有是看到如下代码。

public void execute(Optional<String> nameOptional) {
   ...
}

如果方法的某个参数可能为null,那么可以使用方法重载,而不是传入一个null。因为代码的实现上揭示业务意图要要好于只表示业务意图,因为在业务上null没有业务意义,如果出现null,而又需要处理相关逻辑,那么可以使用方法重载。

另外,方法调用者将很清晰起作用的参数,也不需要为了调用某个方法而构造Optional。

public void execute() {
     execute(null);
}

public void execute(String name) {
    ...
}

上面的代码避免了对外方法的意图模糊,同时也避免了部分的重复代码。

01.02 避免多行 if() 语句

原因: 

1. 如果在使用Optional, 还是出现多行的 if(xxxOptional.isPresent()) ...之类代码, 那跟不用Optional的 if(xxx == null) 没区别, 节约不了什么成本

“使用了Optional,也没有感觉逻辑变变简单啊,每次都得get()方法”,这是工作中听到的刚刚接触Optional的开发人员的表述。

问题在哪里呢?如果我们有一把把核桃夹子,但是每次用这把核桃夹子做的事情都是砸核桃,那么就发现和用锤子砸也没有什么区别,结果都是碎了一地。

我们都说代码时重构出来的,而不是设计出来的。所以实现的时候如果对Optional不熟悉可以使用if来判断,重构的时候可以试着寻找一些能够有更好的解决办法。因为switch语句本来就是坏味道,寻找的方向可以先看看Optional除了提供了get方法,还提供了哪些方法,它们都是做什么用途的。

02 正确使用姿势

02.01 返回值中用Optional显式处理

如果实际实现中需要我们将null值返回,我们可以return一个Optioanl对象回去,这样该方法的调用者就必须就知道返回中有可能为null,并对其进行特定的处理。

public Optional<Data> execute() {
    ...
    return Optional.empty();
}

 

02.02 适当的时候使用Exception

并不是找不到结果我们就只能选择返回Optional.empty(),除非逻辑需要继续执行而不期望中断,否则我们可以直接选择抛出异常。

例如,根据username、password寻找用户的方法,如果找不到用户,可以直接抛出InvalidUsernameOrInvalidPasswordException。

public User login(String name, String password) {
    ...
    
    throw new InvalidUsernameOrInvalidPasswordException();
}

那么,外层要么进行异常处理,要么Project进行全局异常捕获,统一进行处理。

02.03 使用Optional Lambda

在01.02中提到了因为对Optional提供的方法不熟悉,而感觉和null值判断没有多大区别。那么推荐根据业务场景来选择Optioanl Lambda的写法。

String name = computer.flatMap(Computer::getSoundcard)
    .flatMap(Soundcard::getUSB)
    .map(USB::getVersion)
    .orElse("UNKNOWN");

上面写法要比下面的写法清晰很多。当然这需要保持好奇心,多学习一点工具类提供的方法,同时别总是制作简单的搬砖工作。

String version = "UNKNOWN";
if (computer != null) {
    Soundcard soundcard = computer.getSoundcard();
    if (soundcard != null) {
        USB usb = soundcard.getUSB();
        if (usb != null) {
             version = usb.getVersion();
        }
    }
}

 

参考


02.03最终的代码来源

发布了103 篇原创文章 · 获赞 127 · 访问量 107万+

猜你喜欢

转载自blog.csdn.net/guyue35/article/details/104410292