关于java:Effective-Java第54条返回零长度的数组或者集合而不是null

8次阅读

共计 2892 个字符,预计需要花费 8 分钟才能阅读完成。

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

正文完
 0