使用Optional解决长调用链NPE问题

  Java NPE即Null Pointer Exception,如果一次的调用链很长,一旦中间出现了null就很难判断是哪一层为null了。(羡慕Kotlin有?.这种调用)

举个例子,现在有一个简单的类:

public class Simple {
    List<String[]> list;

    public List<String[]> getList() {
        return list;
    }

    public void setList(List<String[]> list) {
        this.list = list;
    }
}

我们的需求是:判断一个Simple对象的list里面的第一个String数组的第一个元素是否以“10”开头,你可能会这么写:

public boolean checkSimple(Simple simple) {
    return simple.getList().get(0)[0].startsWith("10");
}

如果你直接这么写,那么恭喜你,不仅可能会出现空指针异常,还有可能出现数组越界异常,所以我们在调用的时候需要进行null判定:

public boolean checkSimple(Simple simple) {
    if (simple != null) {
        List<String[]> list = simple.getList();
        if (list != null && list.size() > 0) {
            String[] strings = list.get(0);
            if (strings != null && strings.length > 0) {
                String string = strings[0];
                if (string != null) {
                    return string.startsWith("10");
                }
            }
        }
    }

    return false;
}

我们需要去判断中间出现的每一个对象是否为null,然后才能进行下一步,非常的繁琐。

但是如果使用Optional类则比较简洁了:

public boolean checkSimple(Simple simple) {
    return Optional.ofNullable(simple)
            .map(simple1 -> simple.getList())
            .map(list -> list.size() > 0 ? list.get(0) : null)
            .map(strings -> strings.length > 0 ? strings[0] : null)
            .map(s -> s.startsWith("10"))
            .orElse(false);
}

不过有个缺点是写起来爽了,但是可读性还真没有if判断好。如果不熟悉这种写法的话,可能第一眼还真看不出来意图是什么。


另外,使用Optional的时候尽量不要这么用:

if (optional.isPresent()) {
    Object obj = optional.get();
    //do something
}

一是因为这么用和直接判空没什么区别,二是在调用get()的时候,如果其中元素为null,会直接抛出NoSuchElementException,所以尽量不要使用get()方法。

正确的应该是这么用:

optional.ifPresent(obj -> {
    //do something
});

用上Optional之后代码的简洁性会有提高,也更容易写出清爽干净的代码。

标签: Java

添加新评论