tl; dr我的意见是+
在检查值相等时使用一元触发操作数之一上的拆箱操作,否则简单地使用数学运算符。基本原理如下:
已经提到过,==
用于比较的Integer
是身份比较,这通常不是程序员想要的,目的是进行值比较。仍然,我已经就如何在代码紧凑性,正确性和速度方面最有效地进行比较做了一些科学工作。
我使用了通常的方法:
public boolean method1() {
Integer i1 = 7, i2 = 5;
return i1.equals( i2 );
}
public boolean method2() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2.intValue();
}
public boolean method3() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2;
}
public boolean method4() {
Integer i1 = 7, i2 = 5;
return i1 == +i2;
}
public boolean method5() { // obviously not what we want..
Integer i1 = 7, i2 = 5;
return i1 == i2;
}
并在编译和反编译后得到以下代码:
public boolean method1() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
return var1.equals( var2 );
}
public boolean method2() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method3() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method4() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method5() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2 == var1 ) {
return true;
} else {
return false;
}
}
如您所见,方法1调用Integer.equals()
(很明显),方法2-4产生完全相同的代码,通过展开包装的值.intValue()
,然后直接比较它们,而方法5触发身份比较,这是错误的方法比较值。
由于(例如JS已经提到的)equals()
会产生开销(必须这样做instanceof
并且必须进行未经检查的强制转换),因此方法2-4将以完全相同的速度工作,值得注意的是,在紧密循环中使用时,方法2-4比方法1更好,因为HotSpot并非如此可能优化演员和演员instanceof
。
与其他比较运算符(例如<
/ >
)非常相似-它们将触发拆箱,而compareTo()
不会使用--但这一次,HS高度优化了该操作,因为intValue()
这只是一种吸气方法(被优化的主要候选者)。
在我看来,将很少使用的版本4是最简洁的方式-每一个经验丰富的C / Java开发人员都知道,一元加在大多数情况下等于投地int
/ .intValue()
-虽然它可能是一个小WTF的某一时刻(主要是那些谁没(在其生命周期中不使用一元加号),可以说它最清楚,最简洁地显示了其意图-它表明我们想要一个int
操作数的值,同时也迫使另一个值取消装箱。毫无疑问,它也i1 == i2
与用于原始int
值的常规比较最为相似。
我出于性能和一致性的考虑,投票赞成i1 == +i2
&i1 > i2
拒绝Integer
对象的样式。它还使代码可移植到基元,而不更改类型声明以外的任何内容。使用命名方法似乎给我引入了语义干扰,类似于广受批评的bigInt.add(10).multiply(-3)
样式。