写点什么

《Effective Java》第 54 条:返回零长度的数组或者集合,而不是 null

作者:okokabcd
  • 2022 年 8 月 14 日
    山东
  • 本文字数:2125 字

    阅读完需:约 7 分钟

《Effective Java》第54条:返回零长度的数组或者集合,而不是null

《Effective Java》第 54 条:返回零长度的数组或者集合,而不是 null

一、问题

如果一个方法返回类型是 list,如果结果为空的情况下返回 null 的情况并不少见,如下:


public class Shop_Version1 {    private final List<Cheese> cheesesInStock = new ArrayList<>();
public Shop_Version1(boolean initFlag) { if (initFlag) { cheesesInStock.add(Cheese.STILION); } }
/** * @return a list containing all of the cheeses in the shop, * or null if no cheeses are available for purchase. */ public List<Cheese> getCheeses() { return cheesesInStock.isEmpty() ? null : new ArrayList<>(cheesesInStock); }}
复制代码


这样做有一个坏处:调用这个方法的地方必须来处理 null 返回值,这样很容易出错。


有的认为这样做的好处是:这样做避免了分配零长度的容器所需要的开销。这种说法是站不住脚的,第一,在这个级别上是没有必要担心性能的。第二,不需要分配零长度的集合或者数组,也可以返回它们,如下:


public class Shop_Version2 {    private final List<Cheese> cheesesInStock = new ArrayList<>();
public Shop_Version2(boolean initFlag) { if (initFlag) { cheesesInStock.add(Cheese.STILION); } }
/** * @return a list containing all of the cheeses in the shop, * or empty list if no cheeses are available for purchase. */ public List<Cheese> getCheeses() { return new ArrayList<>(cheesesInStock); }}
复制代码

二、分析

2.1 返回集合情况优化

如果真的分配零长度的集合损害了程序的性能,可以通过重复返回一个不可变的零长度集合,避免了分配的执行,因为不可变对象可以被自由共享。如果返回的是集合,可以使用 Collections.emptySet()或 Collections.emptyList();如果返回的是映射,可以使用 Collections.emptyMap()。这是一个优化,但是几乎用不上,如下:


public class Shop_Version3 {    private final List<Cheese> cheesesInStock = new ArrayList<>();
public Shop_Version3(boolean initFlag) { if (initFlag) { cheesesInStock.add(Cheese.STILION); } }
/** * @return a list containing all of the cheeses in the shop, * or empty list if no cheeses are available for purchase. */ public List<Cheese> getCheeses() { return cheesesInStock.isEmpty() ? Collections.emptyList() : new ArrayList<>(cheesesInStock); }}
复制代码

2.2 返回数组情况

返回数组与返回集合的情形一样,它永远不会返回 null,而是返回零长度的数组。


public class Shop_RetArray_Version1 {    private final List<Cheese> cheesesInStock = new ArrayList<>();
public Shop_RetArray_Version1(boolean initFlag) { if (initFlag) { cheesesInStock.add(Cheese.STILION); } }
/** * @return a array containing all of the cheeses in the shop, * or empty array if no cheeses are available for purchase. */ public Cheese[] getCheeses() { return cheesesInStock.toArray(new Cheese[0]); }}
复制代码


千万不要通过预先分配传入 toArray 的数组来提升性能,这样只会适得其反,如下:


public class Shop_RetArray_Version2 {    private final List<Cheese> cheesesInStock = new ArrayList<>();
public Shop_RetArray_Version2(boolean initFlag) { if (initFlag) { cheesesInStock.add(Cheese.STILION); } }
/** * @return a array containing all of the cheeses in the shop, * or empty array if no cheeses are available for purchase. */ public Cheese[] getCheeses() { return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]); }}
复制代码

2.3 返回数组情况优化

如果分配零长度的数组会伤害性能,可以重复返回同一个零长度的数组,因为所有零长度的数组都是不可变的,如下:


public class Shop_RetArray_Version3 {    private final List<Cheese> cheesesInStock = new ArrayList<>();    private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
public Shop_RetArray_Version3(boolean initFlag) { if (initFlag) { cheesesInStock.add(Cheese.STILION); } }
/** * @return a array containing all of the cheeses in the shop, * or empty array if no cheeses are available for purchase. */ public Cheese[] getCheeses() { return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY); }}
复制代码

三、总结

简而言之,永远不要返回 null,而是返回一个零长度的数组或集合。如果返回 null,那样会使 API 更难以使用,也列容易出错,而且没有任何性能优势。

发布于: 刚刚阅读数: 5
用户头像

okokabcd

关注

还未添加个人签名 2019.11.15 加入

一年当十年用的Java程序员

评论

发布
暂无评论
《Effective Java》第54条:返回零长度的数组或者集合,而不是null_Java_okokabcd_InfoQ写作社区