一般来说,我们写代码时,经常会碰到一些场景,比如从数组里面随机获取一个数据,或者从一个集合里面获取一个对象,例如书中的例子
private final List<Cheese> cheesesInStock=new ArrayList<>();
public Cheese[] getCheeses()
{
if(cheesesInStock.size()==0)
{
return null;
}
....
}
我们要买个Cheese,商店给我们提供,但在这里,把商店里没有Cheese 当做一个特例,这是不合理的,这种写法会导致调用这个方法的地方,获取到值后,必须做一些非空判断,
Cheese[] cheeses=shop.getCheeses();
if(cheeses != null && Arrays.asList(cheeses).contains(Cheese.STILTON))
{
System.out.println("Jolly good, just the thing.");
}
或者可以优化一下,
if(Arrays.asList(shop.getCheeses()).contains(Cheese.STILTION))
{
System.out.println("Jolly good, just the thing.");
}
一旦调用者忽略了,没有做非 null 判断,否则程序就会出现问题,我们可以说是调用者的责任,但我们对外提供方法,还是尽量把方法完善一些,提高方法的使用舒适度,我们可以修改自己的方法,返回一个零长度的数组即可,这样,调用者就不必做多余的判断了。
有人觉得,null的返回比零长度数组更好,因为它避免内存分配,但这种说法不太靠谱,对于这个问题,逻辑出错比性能下降更严重,除非性能要求很高,这里影响了性能,再修改;零长度数组,消耗很小,我们也可以对零长度数组做缓存复用,不必每次都创建一个新的。
private final List<Cheese> cheesesInStock = new ArrayList<>();
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
public Cheese[] getCheeses() {
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
如果是需要list集合,我们也可以做一些操作,如果是空集合,直接复用同一个,例如
public List<Cheese> getCheeseList() {
if (cheesesInStock.isEmpty()) {
return Collections.emptyList();
} else {
return cheesesInStock;
}
}
针对 Collections.emptyList() 方法,看一下源码
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
public static final List EMPTY_LIST = new EmptyList<>();
修饰符 static final,说明是一个静态的不可改变地址值的空集合。
所以,返回数组或集合,如果没有内容的话,尽量返回零长度的集合,非null。