'…!= null'或'null!= …'performance最好?
我写了两种方法来检查性能
public class Test1 { private String value; public void notNull(){ if( value != null) { //do something } } public void nullNot(){ if( null != value) { //do something } } }
并在编译后检查它的字节码
public void notNull(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field value:Ljava/lang/String; 4: ifnull 7 7: return LineNumberTable: line 6: 0 line 9: 7 StackMapTable: number_of_entries = 1 frame_type = 7 /* same */ public void nullNot(); Code: Stack=2, Locals=1, Args_size=1 0: aconst_null 1: aload_0 2: getfield #2; //Field value:Ljava/lang/String; 5: if_acmpeq 8 8: return LineNumberTable: line 12: 0 line 15: 8 StackMapTable: number_of_entries = 1 frame_type = 8 /* same */ }
在这里使用两个操作码来实现if条件:第一种情况是使用ifnull- check顶层的堆栈值是null-,第二种情况是使用if_acmpeq- check顶层的两个值在stack-
那么,这会对性能产生影响吗? (这将帮助我certificate首先执行null在性能方面以及在可读性方面都是好的:))
比较生成的字节码几乎没有意义,因为大部分优化都是在JIT编译器运行时发生的。 我会猜测在这种情况下,表情是同样快速的。 如果有任何区别,那可以忽略不计。
这不是你需要担心的事情。 寻找大的图片优化。
如果速度(或者内存/无论是哪种情况)的增益可以忽略不计,则不要以可读性为代价进行优化。 我认为!=null
通常更具可读性,所以使用它。
像这样的问题,很难知道JVM有多聪明(尽pipe答案“如果可能的话通常很聪明”,而且在这种情况下看起来很可能)。 但是可以肯定的是,testing它:
class Nullcheck { public static class Fooble { } Fooble[] foo = {null , new Fooble(), null , null, new Fooble(), null, null, new Fooble() }; public int testFirst() { int sum = 0; for (int i=0 ; i<1000000000 ; i++) if (foo[i&0x7] != null) sum++; return sum; } public int testSecond() { int sum = 0; for (int i=0 ; i<1000000000 ; i++) if (null != foo[i&0x7]) sum++; return sum; } public void run() { long t0 = System.nanoTime(); int s1 = testFirst(); long t1 = System.nanoTime(); int s2 = testSecond(); long t2 = System.nanoTime(); System.out.printf("Difference=%d; %.3f vs. %.3f ns/loop (diff=%.3f)\n", s2-s1,(t1-t0)*1e-9,(t2-t1)*1e-9,(t0+t2-2*t1)*1e-9); } public static void main(String[] args) { Nullcheck me = new Nullcheck(); for (int i=0 ; i<5 ; i++) me.run(); } }
在我的机器上,这产生了:
Difference=0; 2.574 vs. 2.583 ns/loop (diff=0.008) Difference=0; 2.574 vs. 2.573 ns/loop (diff=-0.001) Difference=0; 1.584 vs. 1.582 ns/loop (diff=-0.003) Difference=0; 1.582 vs. 1.584 ns/loop (diff=0.002) Difference=0; 1.582 vs. 1.582 ns/loop (diff=0.000)
所以答案是:不,根本没有意义的区别。 (而JIT编译器可以在重复运行的次数相同的情况下find额外的技巧来加速每个技巧。)
更新 :上面的代码运行一个临时基准。 使用JMH (现在它存在!)是帮助避免(一些)微小基准陷阱的好方法。 上面的代码避免了最糟糕的陷阱,但它没有给出明确的错误估计,并忽略了其他有时很重要的事情。 这几天:用JMH! 另外,如果有疑问,运行你自己的基准。 细节有时很重要 – 对于像这样简单的事情,并不是很常见,但是如果对你来说真的很重要,你应该检查一个尽可能接近你的生产条件。
除了避免在C中偶然赋值的辛苦智慧(这有利于将二元运算符置于左边)之外,我发现左边的常量更具可读性,因为它将关键值置于最显着的位置。
通常一个函数体只会使用一些variables,而且通常通过上下文的方式显示哪个variables正在被检查。 通过把常数放在左边,我们更接近模拟switch
和case
:给定这个variables,select一个匹配的值。 看到左边的价值,一个侧重于所select的特定条件。
当我扫描
if (var == null)
我读到:“我们正在检查var
,我们正在比较它的平等性,反对……啊,null。 相反,当我扫描
if (null == var)
我认为,“我们看到价值是否为零,是的,我们正在检查。 这是一个更强的认识
if (null != var)
我的眼睛只是立即采取了。
这种直觉来自习惯的一致性,倾向于阅读写作内容,并且写出喜欢阅读的内容。 一个人可以学习,但是这不是客观真实的,因为其他人在这里回答说左边的variables是更清楚的。 这取决于首先要expression什么样的方面。
看到字节码的差异是令人着迷的。 感谢分享。
差异将是可以忽略的,所以去最可读的( != null
imo)
为了便于阅读,我会坚持(value!= null)。 但是你总是可以使用断言。
像这样微小的优化是编译器的工作,特别是在像Java这样的高级语言中。
虽然这里严格无关,但不要过早优化!
先将null
似乎会生成一个额外的字节码,但除此之外,可能不会有性能差异。
就个人而言,我不担心performance,直到担心performance。
我会使用notNull()
方法,只是如果你忘了!
并意外键入null = value
。
哦,如果你问最终的performance,不要创build额外的类或方法。 即使静态方法也需要一些时间,因为Java类加载器需要JIT加载它。
所以,无论何时你需要检查一个variables是否为null,你只要testing它
if (x == null)
要么
if (null == x)
坦率地说,我认为select其中之一的绩效奖金很容易被引入不必要方法的开销所抵消。
在编码过程中,你可以忽略这个非常精确的优化
正如你可以看到,不同的performance是非常less的。 不要担心小事情总是更好地关注algorithm。 显然可读性是一个因素。
从这个angular度来看,performance没有显着差异。
但是,首先写空字符来排错错误是有用的。
例如,如果您习惯写这个代码:
if (obj == null)
可能被误写为:
if (obj = null)
从编译器的angular度来看,这很好。
但是,如果您习惯于将代码编写为:
if (null == obj)
并写错了:
if (null = obj)
编译器会让你知道你在那一行犯了一个错误。
字节码只是源代码的简单翻译。