萌新在Discord上问我Optional这个东西到底是什么,干啥用的。这个Optional是Java 8中引入的“新”特性。简单地说:但凡用Optional包裹的变量在获取其值之前都必须进行非空判断。说白了,就是一个带有强制性非空校验的Wrapper。
举个例子:
public class DataProvider {
...
/**
* 通过提供的参数name在数据库中查找Person
**/
public Person findOneByName(String name) {
....
return person;
}
}
上面的DataProvider.findOneByName(name)方法返回一个Person实例。如果,数据库中不存在所查找的人,这个方法返回null,否则,返回Person。那么,下面的调用代码可能需要进行这样的非空判断:
public class MyClass {
....
private void processPerson() {
....
Person person = dataProvider.findOneByName("Joe");
if (person == null) {
//person is null, log, throw exception, etc.
} else {
//process person.
}
}
}
如果写DataProvider的人没有良好的注释或说明findOneByName方法可能返回空值,或者,调用findOneByName方法的人没注意到这一点而忘记做非空判断。那么,在调用findOneByName方法时很有可有会出现NPE(NullPointerException)。为什么说是“很有可能”?因为如果查询的Person在数据库中存在的话,调用代码端就不会出现NPE。
我们现在用Optional来改写一下DataProvider中的findOneByName方法。
public class DataProvider {
...
/**
* 通过提供的参数name在数据库中查找Person
**/
public Optional<Person> findOneByName(String name) {
....
return Optional.ofNullable(person); //显式的告诉JVM这个person实例可能是个null值。
}
}
在上面的代码中,findOneByName方法返回一个用Optional包裹的person,而非直接person。这么一搞,在调用这个方法时,调用端拿着Optional<Person>就没法直接当成Person来用了。想用,可以,先解包。所以,看下面的代码:
public class MyClass {
....
private void processPerson() {
....
Optional<Person> optionalPerson = dataProvider.findOneByName("Joe");
Person person = null;
if (optionalPerson.isPresent()) { //判断Optional中的Person是否为null。
person = optionalPerson.get(); //从Optional中取出Person。
//process person.
} else {
//person is null, log, throw exception, etc.
}
}
}
当然,Optional还提供了很多方法,结合lambda表达式,可以大大精简if-else代码结构,比如:orElse()和orElseGet()等。你们自己摸索去吧。本文已经解释清楚了Optional的意图、作用和基本用法。