草庐IT

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

okokabcd 2023-04-17 原文

《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更难以使用,也列容易出错,而且没有任何性能优势。

有关《Effective Java》第54条:返回零长度的数组或者集合,而不是null的更多相关文章

  1. ruby-on-rails - unicode 字符串的长度 - 2

    在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

  2. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  3. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  4. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  5. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  6. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  7. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  8. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  9. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  10. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

随机推荐