像下面这样的代码并不少见:
?
class="java"> private final List<Cheese> cheesesInStock = ...; public Cheese[] getCheeses(){ if (cheesesInStock.size() == 0) { return null; } }
?
?
把没有奶酪(cheese)可买的情况当作一种特例,这是不合理的,这样做会要求客户端中必须额外的代码来处理null返回值,例如:
?
Cheese[] cheeses = shop.getCheeses(); if (cheeses != null) { Arrays.asList(cheeses).contains(Cheese.STILTON); System.out.println("good just the thing"); }
? 而不是下面这段代码:
if (Arrays.asList(shop.getCheeses()).contains(Cheese.STILTON)) { System.out.println("good just the thing"); }
?
? ? ? ?对于一个返回null而不是零长度数组或者集合的方法,几乎每次用到该方法的时候都需要这种曲折的处理方式。这样做很容易出错,因为编写客户端程序的程序员可能会忘记写这种专门的代码来处理null返回值。这样的错误也许几年都不会被注意到,因为这样的方法通常返回一个或者多个对象,。返回null而不是零长度数组也会使返回数组或者集合的方法本身便得更加复杂,这一点虽然不是特别重要,但是也值得注意。
?
? ? ? 有时候会有人认为:null返回值比零长度数组更好,因为他避免了分配数组所需要的开销,这种观点是站不住脚的,原因有一下两点:
? ? ? ? ? 第一,在这个级别上担心性能问题是不明智的,除非分析表明这个方法正是造成性能问题的真正源头。
? ? ? ? ? 第二,对于不返回任何元素的调用,每次都返回同一个零长度数组是有可能的,因为零长度数组是不可变的,而不可变对象有可能被自由地共享。实际上当你使用标准做法把一些元素从一个集合转存到一个类型化的数组中时,他正是这样做的。
?
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0]; public Cheese[] getCheeses(){ return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY); }
? ? ? ?在这种习惯用法中,零长度数组常量被传递给toArray()方法,比指明所期望的返回值类型。正常情况下,toArray()方法分配了返回数组,但是,如果集合是空的,他将使用零长度的输入数组,Collection.toArray(T[])的规范保证:如果输入数组大到足够容纳这个集合,他就将返回这个输入的数组,因此,这种做法永远也不会分配零长度数组,
?
同样的,集合值的方法也可以做成在每当需要返回空集合时都返回同一个不可变的空集合。collections.emptySet、emptyList和emptyMap方法提供的正是你所需要的,如下所示:
public List<Cheese> getCheesesList(){ if (cheesesInStock.isEmpty()) { return Collections.emptyList(); }else { return new ArrayList<Cheese>(cheesesInStock); } }
?
? ? ? ?简而言之:返回类型为数组或者集合的方法没有理由返回null,而不是返回一个零长度的数组或者集合。这种习惯做法(指返回null)很有可能是从C程序设计语言中没有沿袭过来的,在C语言中,数组长度是与实际的数组分开返回的。在C语言中,如果返回的数组长度为零,再分配一个数组就没有任何好处。
?
?