简而言之,我的意见是在检查值相等时使用一元+
触发其中一个操作数的拆箱,否则只需使用数学运算符。下面是理由:
已经提到过,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() {
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()
则不会 - 但这次,操作非常可优化,因为intValue()
只是一个getter方法(被优化掉的主要候选人)。
在我看来,很少使用的版本4是最简洁的方式 - 每个经验丰富的C/Java开发人员都知道一元加号在大多数情况下等同于强制转换为
int
/
.intValue()
- 尽管对于一些人来说可能有点
WTF(主要是那些从未使用过一元加号的人),但它可以明确和简洁地显示意图 - 它表明我们想要一个操作数的
int
值,同时强制另一个值解包。这也无疑与用于原始
int
值的常规
i1 == i2
比较最相似。
我的投票是支持
i1 == +i2
和
i1 > i2
样式的
Integer
对象,出于性能和一致性的原因。它还使代码可移植到原语而不需要更改除类型声明之外的任何内容。对我来说,使用命名方法似乎像引入语义噪声,类似于备受批评的
bigInt.add(10).multiply(-3)
样式。
==
而不是equals
得到了正确的结果,这可能是因为装箱的数字被内部化或以其他方式被重复使用(作为编译器优化,可能是原因)。提问这个问题的原因是为了找出内部发生了什么,而不是看起来发生了什么。(至少我在这里的目的就是这样。) - Jim Pivarski