16

程序员你是如何降低NPE的?

 3 years ago
source link: https://segmentfault.com/a/1190000024472872
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

biUbmaA.png!mobile

程序员,如果系统突然报了一个空指针异常,你肯定像吞了一只苍蝇一样尴尬。

那么如何在日常开发过程中降低NPE?

问题 回答 现状 返回空值会出现大量的空指针异常 目的 改进方法的返回值,降低出现空指针异常 实现路径 方法返回空集合或者空数组

跟我来!

背景

下面的方法看起来很常见。

private final List<Chesse> chessesInStock= ...

public List<Cheese> getCheeses(){
    return cheesesInStock.isEmpty()?null:new ArrayList<>(cheesesInStock);
}

假如你去购买芝士的时候没有可用的芝士,似乎没有理由特别指出这种场景。

但是你这么做的话,客户端需要添加额外代码来处理可能返回空值的情况。示例代码如下:

List<Cheese> cheeses = shop.getCheeses();

if(cheses != null && cheeses.contains(Cheese.STILTON)){
    System.out.println("jolly good");
}

每一个返回空值的方法都使用上面这种处理方式,应该替换为返回一个空集合或者空数组。

这是一种错误的趋势, 因为程序员些客户端代码可能会忘记写特殊代码来处理返回的空值。

这个错误可能会持续很长时间,因为这样的方法通常会返回一个或多个对象。

不返回空集合空数组的争论

返回空值替换为返回空容器也会使得方法的实现变得复杂。

通常争论的是:返回空值比返回空集合更好是因为创建一个空的容器有性能消耗。

这个论点不对,原因有两点:

一,没有必要担心性能除非有证据显示创建一个空容器整的有损性能;

二,你可以返回一个空集合或者数组而不用创建它们。

返回空集合

下面是一个典型的代码返回一个可能的空集合,通常,这就是你所需要的。

public List<Cheese> getCheeses(){
    return new ArrayList<>(cheeseInStock);
}

没有证据证明创建一个空集合会有损性能,你可以返回一个相同的不可变空集合来避免创建空集合。因为不可变对象是可以被自由共享的,下面是使用代码。

需求场景 代码 空List Collections.emptyList() 空Set Collections.emptySet() 空Map Collections.emptyMap()

但是记住,以上这些操作是只是优化,很少被调用,如果你认为你需要它,在调用前后进行性能对比,确保它真的有用。

public List<Cheese> getCheeses(){
    return cheesesInStock.isEmpty()?Collections.emptyList():new ArrayList<>(cheesesInStock);
}

返回空数组

使用数组的场景跟集合是相同的,永远不要返回空值,应该返回一个长度位0的数组,常常,你应该简单的返回一个有适当长度的数组,也许长度是0。

注意我们传递一个长度为0的数组到toArray方法中来代表期望的返回类型;

public Cheese[] getCheeses(){
    return cheesesInStock.toArray(new Cheese[0]);
}

如果你认为创建一个长度为0的数组会降低性能,你可以返回同一个长度为0的数组,因为所有长度为0的数组都是不可变的;

private static final Cheese[] EMPTY_ARRAY= new Cheese[0];

public Cheeses[] getCheeses(){
    return cheesesInStock.toArray(EMPTY_ARRAY);
}

在优化版本中,我们传递了同一个空的数组到每一个toArray的调用,这个数组将会从getCheeses返回,无论cheesesInStock是不是空的,不要期望预分配数组可以提高性能,研究显示这是适得其反的。

return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);

小结

如果你只能记住一句话: 返回空集合或者数组而不要返回空值

返回空值会让你的API更难使用并且更容易出错,并且无性能优势;

Z7Z7zqm.png!mobile

原创不易,关注诚可贵,转发价更高!转载请注明出处,让我们互通有无,共同进步,欢迎沟通交流。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK