java—检查对象是否为空的最快方法
有人告诉我这样做更快java—检查对象是否为空的最快方法,java,performance,optimization,Java,Performance,Optimization,有人告诉我这样做更快 if(null == object) vs做这件事 if(object == null) 我认为没有区别。请确认效率/性能相同 注意。。。我的朋友已经做了一个性能测试来证明第一个稍微快一点 更新为什么有些人会这样做: 假设您意外地使用“=”而不是预期的相等检查(如“=”)进行赋值,如果您首先使用null,则第一个将给出编译器错误。所以从图形上看它更好 这两个表达式之间实际上没有太大的差异,它们运行速度一样快。如果有区别的话,我认为这不值得努力 人们首先编写非变量操作数
if(null == object)
vs做这件事
if(object == null)
我认为没有区别。请确认效率/性能相同
注意。。。我的朋友已经做了一个性能测试来证明第一个稍微快一点
更新为什么有些人会这样做:
假设您意外地使用“=”而不是预期的相等检查(如“=”)进行赋值,如果您首先使用null,则第一个将给出编译器错误。所以从图形上看它更好 这两个表达式之间实际上没有太大的差异,它们运行速度一样快。如果有区别的话,我认为这不值得努力
人们首先编写非变量操作数的唯一原因是为了避免在像C这样的语言中意外(语法上仍然正确)使用赋值运算符。那些从这些语言迁移到Java的人可能会继续这种做法。应该没有区别。出现这种符号是因为许多人使用赋值运算符而不是比较运算符,这导致了许多难以发现的bug。例如:
if(null = object) {
//compiler throws error that you can't assign null
}
编辑:正如乔恩指出的,这在其他语言中是可能的。我的猜测是,这种习惯一直延续到爪哇岛
@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应该被考虑到帐户中。我编写了一个程序来测试这一点。它所做的只是重复调用两个方法。这些方法的唯一内容是我们想要测试其性能的两个比较
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秒后的结果:
正如您所看到的,在
a()
中,CPU时间缩短了近四倍。这表明比较s==null
确实比null==s
快,如果(null==object)和if(object==null)都相同。它们都具有相同的性能,因此,切换顺序对于这两个表达式并不重要。我正在使用以下代码进行测试:
public class TestNull {
public void left(String s) {
if (s == null);
}
public void right(String s) {
if (null == s);
}
}
我用JavaC1.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个变量
我不确定ifnonnull
和if_acmpne
之间的性能差异,但是如果没有,那么我想虽然没有太大的差异,“正确”的比较应该会更慢,以便在堆栈上做更多的工作
但是,有人能告诉我为什么编译器不重写代码吗 这纯粹是风格上的差异。在我的测试中,我得到了第一个测试用例的长时间运行,这可以归因于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) );
}
我将建立在@James answer之上:
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\u acmpne
,它比较加载的acost\u null
,它将其视为常量
显然如果acmpne
比ifnonnull
慢:
if_acmpne
将顶部的两个对象引用从堆栈中弹出,然后
比较它们。如果两个对象引用不相等(即如果
它们引用不同的对象),执行分支到地址
(pc+branchoffset),其中pc是if_acmpne操作码的地址
在字节码和branchoffset中,是一个16位有符号整数参数
在字节码中的if_acmpne操作码之后。如果对象
引用引用同一个对象,执行将在下一个
指示
ifnonnull
从操作数堆栈中弹出顶部对象引用。如果
对象引用不是特殊的空引用,执行分支
至地址(pc+branchoffset),其中pc是
字节码和branchoffset中的ifnonnull操作码是16位有符号的
字节码中ifnonnull操作码后面的整数参数。如果
堆栈上的对象引用为null,将在
下一个指令
因此
如果(s==null)
必须更快(与问题中OP所述相反)。您如何通过编写一个测试程序来确认差异并计时?或者看看生成的字节码。也许这个问题可以推广到其他有趣的作业或比较。我不明白为什么我会投反对票。我运行了Chechus的测试,我确实看到了差异,尽管这不会影响性能。那是我唯一的问题。如果我有三千张这样的支票呢?那么我想知道影响。这就是我想知道的。@OldProgrammer这些优化不是在运行时发生的吗?有什么理由要查找字节码吗?我在程序上附加了一个分析器来测试这个。看起来OP听到的谣言是真的,至少在我的机器上是这样。我无法将结果放入评论中,所以我发布了自己的答案。如果有人能解释我得到的结果,请随意在你自己的答案中使用我的结果,然后让我知道,这样我就可以删除我的结果。这个符号是由于人们在其他语言中犯作业错误而产生的如果(object=null){
在Java中也是无效的…@JonSkeet-True,我认为人们的习惯只是延续到了Java中。与我的测试相比,JIT似乎发挥了作用并进行了优化,因为我的测试始终与此结果相反(见下面我的答案)!使用与Oracle 1.7 JRE相同的代码,并在该代码运行一段时间后附加探查器,I g
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
}