• 《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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这样做有一个坏处:调用这个方法的地方必须来处理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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    二、分析

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    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]);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    千万不要通过预先分配传入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()]);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    三、总结

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

  • 相关阅读:
    Ceph入门到精通-生产日志级别设置
    太神了!开源大佬的SpringBoot+微服务架构笔记,一般人真肝不出来
    C++ 中的 模板类 简介
    持续集成部署-k8s-深入了解 Pod:Pod 的基础操作
    C++入门应该注意的问题(内联函数和C的宏)
    电商业务--技术负责人 250K*15
    安卓手机误删文件恢复
    linux4.1.15内核移植到野火PRO开发板开发板
    大学经典题目:Java输出杨辉三角形
    K8s---Pod搭建LNMP
  • 原文地址:https://blog.csdn.net/ln_ydc/article/details/126337118