java 如何优雅地处理空值
2021-06-10 本文已影响0人
飞鹰雪玉
场景
存在一个UserService用来提供用户查询的功能。
public interface UserService(){
List<User> list();
User getUser(Integer id);
}
疑惑
list():如果没有数据,返回null还是空集合?
getUser(Integer id):如果没有对应id的用户,返回null还是抛一个异常?
分析
先分析list()
一般实现有这样:
public List<User> list(){
List<User> userList = userMapper.list();
if (userList.size() == 0){
return null;
}
return userList;
}
这段代码返回是null
, 对于集合这样返回值,最好不要返回null
,因为如果返回了null
,会给调⽤者带 来很多麻烦。你将会把这种调用风险交给调用者来控制。
如果调用者是⼀个谨慎的⼈,他会进⾏是否为null的条件判断。如果他并⾮谨慎,或者他是⼀个⾯向接⼝编程的狂热分⼦(当然, ⾯向接⼝编程是正确的⽅向),他会按照⾃⼰的理解去调⽤接⼝,⽽不进⾏是否为null的条件判断,如果这样的话,是⾮常危险 的,它很有可能出现空指针异常!
为此我们进行优化:
public List<User> list(){
List<User> userList = userMapper.list();
if (userList.size() == 0){
return new ArrayList<>();
}
return userList;
}
对于list()
接口来说,它⼀定会返回List,即使没有数据,它仍然会返回List(集合中没有任何元素);
通过以上的修改,我们成功的避免了有可能发⽣的空指针异常,这样的写法更安全!
getUser(Integer id)
一般实现方式有以下
public User getUser(Integer id){
return userMapper.selectById(id);
}
通过代码的时候得知它的返回值很有可能是null! 但我们通过的接⼝是分辨不出来的! 这个是个⾮常危险的事情。尤其对于调⽤者来说!
解决方案一:
在接口说明时补充⽂档,⽐如对于异常的说明,使⽤注解@exception:
/**
* 根据id获取用户对象
* @param 用户id
* @return 用户对象
* @exception UserNotFoundException
*/
User getUser(Integer id);
我们把接⼝定义加上了说明之后,调⽤者会看到,如果调⽤此接⼝,很有可能抛出UserNotFoundException
这样的异常。这种⽅式可以在调⽤者调⽤接⼝的时候看到接⼝的定义,但是,这种⽅式是“弱提⽰”的!如果调⽤者忽略了注释,有可能就对业务系统产⽣了⻛险,这个⻛险有可能导致⼀个亿!
解决方案二:
引⼊jdk8的Optional
,或者使⽤guava的Optional
/**
* 根据id获取用户对象
* @param 用户id
* @return 用户对象
*/
Optional<User> getUser(Integer id);
Optional
有两个含义: 存在 or 缺省。
实现
public Optional<User> getUser(Integer id){
return Optional.ofNullable(userMapper.selectById(id));
}