前言
工作多年,最近在项目中一个地方Integer比较大小,竟然踩坑了。
那么你知道Integer比较大小的正确写法吗?
一、错误说明
先看一下下面这个demo,大家猜下,是相等还是不相等?
@Test public void integerTest(){ Integer status = 1; if("1".equals(status)){ System.out.println("相等"); }else{ System.out.println("不相等"); } }
执行结果:
原因分析:
equals方法的调用者“1”是一个字符串对象,所以这里走的是String对象的equals方法,而不是Integer对象的equals方法。
String对象的equals方法源码:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
说明:
参数如果不是String类型,直接返回false。
二、优化一
那么正确写法是什么?
大部分人可能想到了Integer对象status前置,如下
@Test public void integerTest2(){ Integer status = 1; if(status.equals(1)){ System.out.println("相等"); }else{ System.out.println("不相等"); } }
执行结果:
分析:
结果确实正确。但是大家有想过一点吗,由于程序中,Integer对象是可以为null的。一个为null的对象是不能调用任何方法的,否则就会出现空指针异常。
三、阿里规约的相关说明
这点大家应该都想到了String对象的等值比较,阿里的java规范中也提到的,尽量使用非空常量对象作为方法的调用方。
四、Integer等值比较优化
Integer等值比较优化
@Test public void integerTest2(){ Integer status = null; if(Integer.valueOf(1).equals(status)){ System.out.println("相等"); }else{ System.out.println("不相等"); } }
执行结果:
这样,即使变量status为空,也不会影响equals方法的比较结果。
五、相关建议
1、包装类型等值比较必须使用equals,只有基本类型等值比较使用==
2、调用equals方法时,使用常量和确定有值的对象作为方法的调用方,减少空指针异常。
3、进行equals等值判断的值,推荐采用常量类或枚举类进行封装。
4、偷懒的写法:Integer.valueOf(1).equals(status)。将基本类型转成包装类后再使用equals比较。
六、Integer的缓存说明
@Test public void integerTest2(){ Integer integer1 = 3; Integer integer2 = 3; if(integer1 == integer2){ System.out.println("相等"); }else{ System.out.println("不相等"); } integer1 = new Integer("3"); integer2 = new Integer("3"); if(integer1 == integer2){ System.out.println("相等"); }else{ System.out.println("不相等"); } integer1 = 128; integer2 = 128; if(integer1 == integer2){ System.out.println("相等"); }else{ System.out.println("不相等"); } }
执行结果:
相等 不相等 不相等
说明:
首先说明一点,Integer这个缓存机制,其实对我们写代码来说基本没什么影响,只是对底层数据存储的内存优化。
实际项目开发过程中,Integer的等值比较必须采用equals,而不能使用==。
执行结果说明:
由于==实际比较的是对象的内存地址,而Integer在-128 至 127 范围内采用Integer integer1 = 3这样的方式复制时,会复用已经缓存的对象,所以相等。
采用new的方式会重新声明对象会分配新的内存地址,不使用缓存对象,所以不相等。
超过128的对象不会使用缓存对象,地址都重新分配,所以不相等。
总结
1.包装类型等值比较必须使用equals,基本类型等值比较使用==
2.Integer的缓存范围在-128~127(默认),知道就好,项目中禁止使用 ==来比较Integer的大小。
3、基本类型需要转为包装类型再调用equals方法比较大小
Integer.valueOf(1).equals(status)
4、为了避免魔法值,对参与equals等值比较的值,尽量采用常量类或枚举类进行封装。