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 将以完全相同的速度工作,明显优于方法 1用于紧密循环,因为 HotSpot 不太可能优化演员表和instanceof。
它与其他比较运算符非常相似(例如 </>) - 它们会触发拆箱,而使用 compareTo() 不会 - 但这次,HS 高度优化了该操作,因为 intValue()只是一个 getter 方法(被优化的主要候选者)。
在我看来,很少使用的版本 4 是最简洁的方式 - 每个经验丰富的 C/Java 开发人员都知道一元加号在大多数情况下等于强制转换为 int/.intValue() - 虽然可能有点WTF 对于某些人(主要是那些在他们的一生中没有使用一元加号的人)来说,它可以说是最清楚和最简洁地显示了意图 - 它表明我们想要一个 int 值之一操作数,也强制其他值取消装箱。毫无疑问,它与用于原始 int 值的常规 i1 == i2 比较最为相似。
出于性能和一致性的原因,我对Integer 对象的i1 == +i2 和i1 > i2 样式投了赞成票。它还使代码可移植到原语,而无需更改类型声明以外的任何内容。使用命名方法似乎给我带来了语义噪音,类似于备受批评的 bigInt.add(10).multiply(-3) 风格。