使用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之后代码的简洁性会有提高,也更容易写出清爽干净的代码。