java - 检查对象是否为null的最快方法

时间:2014-07-21 21:44:07

标签: java performance optimization

有人告诉我这样做的速度更快

if(null == object) 

vs做这个

if(object == null)

我认为没有区别。请确认效率/性能是否相同。

注意......我的朋友已经进行了性能测试,以证明第一个稍快一点。

更新为什么有些人这样做: 假设您意外地使用“=”而不是预期的等式检查(例如“==”)进行赋值,如果首先使用null,则第一个将给出编译器错误。如此重要,它更好。

8 个答案:

答案 0 :(得分:6)

我写了一个程序来测试这个。它只是重复调用两种方法。这些方法的唯一内容是我们要测试性能的两个比较。

public class StackOverflow {
    public static void main(String[] args) {
        String s = "";
        while (true) {
            a(s);
            b(s);
        }
    }
    private static void a(String s) {
        if (s == null);
    }
    private static void b(String s) {
        if (null == s);
    }
}

我将一个分析器附加到我的程序中。以下是执行70秒后的结果:

enter image description here

如您所见,a()的CPU时间轻了近四倍。这表明比较s == null确实比null == s更快。

答案 1 :(得分:6)

我将建立在@James回答之上:

public class TestNull {
   public void left(String s) {
       if (s == null);
   }
   public void right(String s) {
       if (null == s);
   }
}

字节码:

public class TestNull {
  ....
  public void left(java.lang.String);
    Code:
       0: aload_1       
       1: ifnonnull     4
       4: return        

  public void right(java.lang.String);
     Code:
       0: aconst_null   
       1: aload_1       
       2: if_acmpne     5
       5: return        
}

首先是更快(当null位于右侧时)因为java有一个字节码命令ifnonnull,它将加载的变量与null进行比较。

第二个因为正在使用另一个命令而变慢:if_acmpne并且它比较了它看作常量的加载aconst_null

显然if_acmpne慢于ifnonnull

  

if_acmpne弹出堆栈顶部的两个对象引用   比较它们。如果两个对象引用不相等(即如果   它们引用不同的对象),执行分支到地址   (pc + branchoffset),其中pc是if_acmpne操作码的地址   在字节码和branchoffset中是一个16位有符号整数参数   跟随字节码中的if_acmpne操作码。如果是对象   引用引用相同的对象,下一步继续执行   指令。

     

ifnonnull从操作数堆栈中弹出顶部对象引用。如果   对象引用不是特殊的空引用,执行分支   到地址(pc + branchoffset),其中pc是地址   字节码和branchoffset中的ifnonnull操作码是16位有符号的   字节码中ifnonnull操作码后面的整数参数。如果   堆栈上的对象引用为null,继续执行   下一条指令。

因此if (s == null)必须更快(与问题中所述的OP相反)。

答案 2 :(得分:2)

我正在使用此代码进行测试:

public class TestNull {
   public void left(String s) {
       if (s == null);
   }
   public void right(String s) {
       if (null == s);
   }
}

我用javac 1.8.0_05编译它,然后检查了字节码:

public class TestNull {
  ....
  public void left(java.lang.String);
    Code:
       0: aload_1       
       1: ifnonnull     4
       4: return        

  public void right(java.lang.String);
     Code:
       0: aconst_null   
       1: aload_1       
       2: if_acmpne     5
       5: return        
}

显然,left只推送并弹出堆栈中的1个变量,而right推送和弹出2.

我不确定ifnonnullif_acmpne之间的性能差异,但如果没有,那么我想虽然没有太大差异,但“正确”比较应该更慢在堆栈上做更多的工作。

然而,有人可以告诉我为什么编译器不会重写代码吗?

答案 3 :(得分:1)

这两个表达式之间确实没有太大的区别,它们运行速度相同。如果有任何差异,我认为这不值得努力。

人们首先编写非变量操作数的唯一原因是为了避免在C语言中使用赋值运算符的意外(在语法上仍然正确)。那些从这些语言迁移到Java的人可能会继续这种做法。

答案 4 :(得分:1)

这纯粹是一种文体差异。在我的测试中,我得到了第一个测试用例的长期运行,这可以归因于JRE设置;其余的迭代表明它们是相同的。

        for( int j = 0; j < 10; j++ )
        {
            Object a = null;
            int i = 0;
            long tik = System.nanoTime();
            while( i < 500000 )
                if( a == null )
                    i++;
            System.out.print( "a:" + (System.nanoTime() - tik) );
            Object b = null;
            i = 0;
            tik = System.nanoTime();
            while( i < 500000 )
                if( null == b )
                    i++;
            System.out.println( " b:" + (System.nanoTime() - tik) );
        }

得到以下结果:

a:826735 b:354261
a:318150 b:314729
a:323472 b:314729
a:314350 b:315869
a:318151 b:316630
a:325753 b:314350
a:316250 b:314350
a:314730 b:321952
a:398733 b:340197
a:328794 b:338676

答案 5 :(得分:0)

应该没有区别。由于许多人使用赋值运算符而不是比较运算符,因此产生了这种表示法,这导致许多难以发现的错误。例如:

if(null = object) {
    //compiler throws error that you can't assign null
}

编辑:正如乔恩所指出的,这在其他语言中是可行的。我的猜测是习惯延续到了Java的土地上。

答案 6 :(得分:0)

@Test
public void testNullCheck() throws Exception {
    Object o = null;

    long i1 = System.nanoTime();
    if (null == o) {
    }
    long t1 = System.nanoTime() - i1;

    long i2 = System.nanoTime();
    if (o == null) {
    }
    long t2 = System.nanoTime() - i2;

    assertThat(t1).isGreaterThan(t2);
}

我的JVM中的位置:

T2 :116L
T1 :304L

所以是的,至少在实践中存在差异。


编辑:

  

请确认效率/性能是否相同。

不,不一样。但鉴于JIT的存在时间可能相同,因此需要进行新的测试,以便将JIT纳入账户。

答案 7 :(得分:-2)

if(null == object)和if(object == null)两者都相同。它们都具有相同的性能,因此,切换顺序对于这两个表达式并不重要。