如何正确比较Java中的两个整数?

时间:2009-10-03 21:30:44

标签: java integer autoboxing

我知道如果你将盒装原语Integer与常量比较,如:

Integer a = 4;
if (a < 5)

a将自动取消装箱并进行比较。

然而,当您比较两个盒装Integers并希望比较相等或小于/大于?时会发生什么?

Integer a = 4;
Integer b = 5;

if (a == b)

上面的代码会导致检查它们是否是同一个对象,还是会在这种情况下自动取消装箱?

怎么样:

Integer a = 4;
Integer b = 5;

if (a < b)

10 个答案:

答案 0 :(得分:257)

不,= =在Integer,Long等之间检查引用相等 - 即

Integer x = ...;
Integer y = ...;

System.out.println(x == y);

这将检查xy是否引用相同的对象而不是相等的对象。

所以

Integer x = new Integer(10);
Integer y = new Integer(10);

System.out.println(x == y);

保证打印false。 “小”自动装箱值的实习可能会导致棘手的结果:

Integer x = 10;
Integer y = 10;

System.out.println(x == y);

由于拳击规则(JLS section 5.1.7),这将打印true。它仍然是使用的引用相等,但真正的引用相等。

就我个人而言:

if (x.intValue() == y.intValue())

if (x.equals(y))

后者的效率稍差 - Integer.equals(Integer)没有重载,因此必须执行执行时类型检查,而第一个使用的事实是我们已经知道两个对象都是{{1 }}第

幸运的是,Integer知道类型,所以:

compareTo

应该仍然有效率。当然,这是微优化领域,你应该使用你发现最清楚的代码 - 确保它是正确的:)

正如您所说,对于包装器类型(if (x.compareTo(y) < 0) Integer等)和数字类型(Longint等)之间的任何比较,包装器类型值是 unboxed ,测试将应用于所涉及的原始值。

这是二进制数字促销(JLS section 5.6.2)的一部分。查看每个运营商的文档,看看它是否已应用。例如,来自long==JLS 15.21.1)的文档:

  

如果操作数相等   运算符都是数字类型,或   一个是数字类型,另一个是数字类型   可转换(第5.1.8节)为数字   类型,二进制数字促销是   在操作数上执行(第5.6.2节)。

!=<<=>JLS 15.20.1

  

每个操作数的类型   必须是数值比较运算符   一种可转换的类型(§5.1.8)   原始数字类型,或   发生编译时错误。二进制   数字促销是在   操作数(§5.6.2)。如果升职了   操作数的类型是int或long,   然后签名整数比较是   执行;如果这个提升类型是   浮点或双点,然后是浮点数   进行比较。

请注意,如果 类型都不是数字类型,则不会将其视为一部分。

答案 1 :(得分:41)

==仍将测试对象相等性。然而,很容易被愚弄:

Integer a = 10;
Integer b = 10;

System.out.println(a == b); //prints true

Integer c = new Integer(10);
Integer d = new Integer(10);

System.out.println(c == d); //prints false

具有不等式的示例将起作用,因为它们未在对象上定义。但是,通过==比较,仍将检查对象相等性。在这种情况下,当您从盒装基元初始化对象时,将使用相同的对象(对于a和b)。这是一个好的优化,因为原始的盒子类是不可变的。

答案 2 :(得分:14)

从Java 1.7开始,您可以使用Objects.equals

java.util.Objects.equals(oneInteger, anotherInteger);
  

如果参数彼此相等且为false,则返回true   除此以外。因此,如果两个参数都为null,则返回true   如果只有一个参数为null,则返回false。除此以外,   通过使用第一个的equals方法确定相等性   参数。

答案 3 :(得分:10)

==检查引用相等性,但是在编写代码时如下:

Integer a = 1;
Integer b = 1;

Java非常聪明,可以为ab重用相同的不可变,所以这是真的:a == b。好奇,我写了一个小例子来说明java以这种方式停止优化:

public class BoxingLol {
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            Integer a = i;
            Integer b = i;
            if (a != b) {
                System.out.println("Done: " + i);
                System.exit(0);
            }
        }
        System.out.println("Done, all values equal");
    }
}

当我编译并运行它(在我的机器上)时,我得到:

Done: 128

答案 4 :(得分:8)

调用

if (a == b)

大部分时间都会工作,但不保证始终有效,所以不要使用它。

比较两个Integer类的相等性的最正确的方法,假设它们被命名为'a'和'b'是要调用:

if(a != null && a.equals(b)) {
  System.out.println("They are equal");
}

您也可以使用稍快一点的方式。

   if(a != null && b != null && (a.intValue() == b.intValue())) {
      System.out.println("They are equal");
    } 

在我的机器上,99亿次操作使用第一种方法需要47秒,使用第二种方法需要46秒。您需要比较数十亿的值才能看到任何差异。

请注意,'a'可能为null,因为它是一个Object。以这种方式比较不会导致空指针异常。

要比较大于和小于,请使用

if (a != null && b!=null) {
    int compareValue = a.compareTo(b);
    if (compareValue > 0) {
        System.out.println("a is greater than b");
    } else if (compareValue < 0) {
        System.out.println("b is greater than a");
    } else {
            System.out.println("a and b are equal");
    }
} else {
    System.out.println("a or b is null, cannot compare");
}

答案 5 :(得分:6)

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将以完全相同的速度工作,注意更好因为HotSpot不太可能优化演员和演出,因此在紧密循环中使用方法1。 instanceof

它与其他比较运算符非常相似(例如< / >) - 它们将触发拆箱,而使用compareTo()则不会 - 但这一次,操作是高度可优化的由HS intValue()只是一个getter方法(被优化的主要候选者)。

在我看来,很少使用的版本4是最简洁的方式 - 每个经验丰富的C / Java开发人员都知道,在大多数情况下,一元加上等于转换为int / .intValue() - 而它对某些人来说可能是一个小小的 WTF 时刻(大部分是那些在他们的一生中没有使用过一元加号的人),它可以说是最明确,最简洁的意图 - 它表明我们想要一个{{1其中一个操作数的值,也强制另一个值为unbox。与原始int值的常规i1 == i2比较相比,这也是无可争议的。

我的投票适用于int&amp; i1 == +i2对象的i1 > i2样式,无论是性能还是性能。一致性原因。它还使代码可以移植到基元而不需要更改除类型声明之外的任何内容。使用命名方法似乎向我引入了语义噪声,类似于备受批评的Integer样式。

答案 6 :(得分:1)

在我的情况下,我必须比较两个Integer的相等性,而两者都可能是null。搜索了类似的主题,没有发现任何适合的话题。提供了一个简单的实用程序功能。

public static boolean integersEqual(Integer i1, Integer i2) {
    if (i1 == null && i2 == null) {
        return true;
    }
    if (i1 == null && i2 != null) {
        return false;
    }
    if (i1 != null && i2 == null) {
        return false;
    }
    return i1.intValue() == i2.intValue();
}

//considering null is less than not-null
public static int integersCompare(Integer i1, Integer i2) {
    if (i1 == null && i2 == null) {
        return 0;
    }
    if (i1 == null && i2 != null) {
        return -1;
    }
    return i1.compareTo(i2);
}

答案 7 :(得分:0)

因为比较方法必须基于类型int(x == y)或类Integer(x.equals(y))并带有正确的运算符

public class Example {

    public static void main(String[] args) {
     int[] arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};

        for(int j=1; j<arr.length-1; j++)
            if((arr[j-1]!=arr[j]) && (arr[j]!=arr[j+1])) 
                System.out.println("int>"+arr[j]);


    Integer[] I_arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};

        for(int j=1; j<I_arr.length-1; j++)
            if((!I_arr[j-1].equals(I_arr[j])) && (!I_arr[j].equals(I_arr[j+1]))) 
                System.out.println("Interger>"+I_arr[j]);
    }
}

答案 8 :(得分:0)

我们应该始终使用equals()方法比较两个整数。这是推荐做法。

如果我们使用==比较两个整数,由于JVM的内部优化,该整数将适用于一定范围的整数值(从-128到127的整数)。

请参见示例:

案例1:

  

整数a = 100;    整数b = 100;

if (a == b) {
    System.out.println("a and b are equal");
} else {
   System.out.println("a and b are not equal");
}

在上述情况下,JVM使用缓存池中的a和b的值并返回整数对象的相同对象实例(因此是内存地址),我们得到相等的对象。它的优化JVM 用于一定的范围值。

情况2:在这种情况下,a和b不相等,因为它不具有-128到127的范围。

  

整数a = 220;    整数b = 220;

if (a == b) {
    System.out.println("a and b are equal");
} else {
   System.out.println("a and b are not equal");
}

正确的方法:

Integer a = 200;             
Integer b = 200;  
System.out.println("a == b? " + a.equals(b)); // true

我希望这会有所帮助。

答案 9 :(得分:-1)

此方法将两个Integer与null检查进行比较,请参阅tests

public static boolean compare(Integer int1, Integer int2) {
    if(int1!=null) {
        return int1.equals(int2);
    } else {
        return int2==null;
    }
    //inline version:
    //return (int1!=null) ? int1.equals(int2) : int2==null;
}

//results:
System.out.println(compare(1,1));           //true
System.out.println(compare(0,1));           //false
System.out.println(compare(1,0));           //false
System.out.println(compare(null,0));        //false
System.out.println(compare(0,null));        //false
System.out.println(compare(null,null));     //true