Java空指针检查更快的代码执行

时间:2015-02-09 15:40:05

标签: java nullpointerexception typechecking

想象一个方法,它将一个对象作为参数并检查每个循环,然后让我们说一些集合中的其他值,可以根据传入的参数找到/过滤。检查函数开头是否为空指针并立即返回空集合或空指针是一个好习惯,或者最好不要忽略空指针检查,因为每个循环都会处理它,但是函数将需要更多的时间来执行(因为每次迭代的整体)。可以说这个系列并不大(不是那么费时)。

 public ArrayList<Foo> find(Bar bar) {  
        if (bar == null) { // get rid of these part?
            return null;   //
        }                  //  

        ArrayList<Foo> foos = new ArrayList<Foo>();
        for (Foo f: Foo.values()) {
            if (f.someBarCollection.contains(bar)) {
                foos.add(f);
            }
        }

        return foos;
 }

我认为最好检查null并立即返回,如果你知道这是浪费时间做任何进一步的行动,因为你知道他们不需要。所以我偏袒语义而牺牲更短的代码,使事情变得毫无原则。

编辑: 让我再详细说明一下。函数的结果与没有空检查部分的OR相同。问题是,我是否应该检查它,只是为了更好的表达(以及一点性能提升,但这不是问题),但代码会更长(因为增加了检查)?

5 个答案:

答案 0 :(得分:5)

取决于

根据您的API,当收到的参数值为null时,您可以执行以下操作:

  • 抛出异常。可能是IllegalArgumentException或描述这个不良论点的原因的自定义异常。
  • 返回null值,让客户端在其余代码中处理结果。
  • 返回空结果。如果是List(不是ArrayList),您可以返回Collections#emptyList

您使用的API /方法选项,请务必在javadoc中正确记录。

答案 1 :(得分:1)

你是否检查更多的是品味而不是表现。 然而,为了让您的客户更轻松,您应该返回null,而是空集合。

根据用例,您还可以引发异常(如果不允许为空)和/或使用bar注释@NonNull参数以允许使用可插入的检查器。

答案 2 :(得分:1)

取决于预期的bar值。如果nullbar的允许值,那么您的决定是好的。否则最好抛出异常。

答案 3 :(得分:0)

这取决于您希望null传递给此方法的频率(以及是否)。

答案 4 :(得分:0)

要考虑的一件事是面向未来。

如果您可以想象合法集合contains(null)然后让它通过(并返回一个空集合)或抛出异常(可能是IllegalArgumentException)。抛出异常意味着更改不会影响现有合法代码的行为。

除非您考虑在null(通常不推荐)时将bar!=null返回为“空”,否则返回bar==null会有点不一致。

相当正确的是,大多数其他帖子都不鼓励null为“空”。 使用它的唯一原因是性能:

//WARNING - THIS CODE IS NOT FIRST CHOICE
public ArrayList<Foo> find(Bar bar) {  
        ArrayList<Foo> foos = null;
        for (Foo f: Foo.values()) {
            if (f.someBarCollection.contains(bar)) {
                if(foos==null){
                    foos=new ArrayList<Foo>();
                }
                foos.add(f);
            }
        }
        return foos;
 }

Collections.emptyList()很有价值,但任何认为可以修改列表的调用代码都会让UnsupportedOperationException感到惊讶。 因此,将null替换为“空”可能会导致交换NullPointerException(可能不那么频繁且更难发现)UnsupportedOperationException。没有我们想要的那么多进展。

返回本地ArrayList的下一个选择是可怕的:

//DANGER - CODING HORROR!

static final sEmpty=new ArrayList<Foo>();

public ArrayList<Foo> find(Bar bar) {  
        ArrayList<Foo> foos = null;
        for (Foo f: Foo.values()) {
            if (f.someBarCollection.contains(bar)) {
                if(foos==null){
                    foos=new ArrayList<Foo>();
                }
                foos.add(f);
            }
        }
        return foos==null?sEmpty:foos;
 }

在这种情况下,无知代码可能会将元素添加到所谓的空ArrayList,并导致后续调用find()返回它们。花一天时间的好方法就是找到那个!

可悲的是,似乎我们远离Java实现C ++样式const以区分可变和不可变引用。 所以至少在某些情况下,你会留下返回的小垃圾对象或null留给'空'。

在一天结束时,Java库采取的态度是创建和销毁许多小对象是简单的可接受开销(查看像'整数'这样的'盒装'原语)。许多现代JVM都有分代垃圾收集器,旨在与这种风格协调。

所以,如果你还未决定'接受'null

public ArrayList<Foo> find(Bar bar) {  
        if(bar==null){
            throw new IllegalArgumentException("bar==null");
        }
        ArrayList<Foo> foos = new ArrayList<Foo>();
        for (Foo f: Foo.values()) {
            if (f.someBarCollection.contains(bar)) {
                foos.add(f);
            }
        }
        return foos;
 }

否则请顺其自然:

public ArrayList<Foo> find(Bar bar) {  
        ArrayList<Foo> foos = new ArrayList<Foo>();
        for (Foo f: Foo.values()) {
            if (f.someBarCollection.contains(bar)) {
                foos.add(f);
            }
        }
        return foos;
 }

如果这种方法是经证实的瓶颈,则只考虑替代方案。