常言道:“细节决定成败”,编程更是如此。
近期,我参加的一个项目,让我对此体会深刻。
这个项目属于推荐系统的一部分,我负责的一块是进行MapRedcue编程,计算视频之间的相似度!另一个同事就把我计算出来的结果用Sqoop导入到数据库中,供线上调用。
在导入数据的过程中,总是爆出java.lang.NumberFormatException异常,我认为是他那里的原因,他的Sqoop没有进行空行或者空格过滤,我的相似度结果是没有错的。后来他把一部分相似度结果复制到Notepad里面,发现有的数据有空格,他是直接读入,然后进行转换,当然就出现问题了。我不知道Sqoop能不能进行空格过滤,但是,我的程序可以控制输出的结果,所以就对每一个输出结果都调用了java.lang.String类的trim()方法。最终问题解决。
空格,总是会造成一些小问题,但是不容忽视。消除空格,记得调用trim()方法。
另一个问题是基本数据类型的封装类进行比较的时候,可能不是比较的数值,而是内存的地址!
相似度计算的过程中,有一个地方需要进行java.lang.Long类型之间的相等判断。我发现最终的相似度输出结果不正确时,排查原因,最终定位到这里。原来的代码是这样的:
if(lg1 == lg2){
return true;
}
lg1和lg2都是java.lang.Long类型,我在这里是想判断lg1和lg2的数值是否相等,之前,我只是笼统地记得,Java的封装类进行比较的时候会进行转换的,所以就这样写了!但是这样写也可能比较大不是数值,而是他们各自在内存中的地址。
我用Google搜索了这个问题,网上说,java.lang.Float类型和java.lang.Double类型使用“==”进行相等判断需要转换成基本数据类型,java.lang.Integer和java.lang.Long则不需要转换,Java会自动转换的。但是,我自己做的测试跟这种说法有出入。下面是测试代码:
package org.jindao.basic;
/**
* @author
* @date 2013年10月25日 上午7:30:47
*/
public class BasicTest {
public static void main(String[] args) {
Integer ig1 = 3;
Integer ig2 = 3;
System.out.println("Integer ig1 = 3,Integer ig2 = 3 ig1==ig2的结果为:"+(ig1==ig2));
Integer ig3 = new Integer(3);
Integer ig4 = new Integer(3);
System.out.println("Integer ig3 = new Integer(3),Long ig4 = new Integer(3) ig3==ig4的结果为:"+(ig3==ig4));
Long lg1 = 3l;
Long lg2 = 3l;
System.out.println("Long lg1 = 3l,Long lg2 = 3l lg1==lg2的结果为:"+(lg1==lg2));
Long lg3 = new Long(3);
Long lg4 = new Long(3);
System.out.println("Long lg3 = new Long(3),Long lg4 = new Long(3) lg3==lg4的结果为:"+(lg3==lg4));
Float flt1 = 3.2f;
Float flt2 = 3.2f;
System.out.println("Float flt1 = 3.2f,Float flt2 = 3.2f flt1==flt2的结果为:"+(flt1==flt2));
Float flt3 = new Float(3.2);
Float flt4 = new Float(3.2);
System.out.println("Float flt3 = new Float(3.2),Float flt4 = new Float(3.2)) flt3==flt4的结果为:"+(flt3==flt4));
Double db1 = 3.2;
Double db2 = 3.2;
System.out.println("Double db1 = 3.2,Double db2 = 3.2 db1==db2的结果为:"+(db1==db2));
Double db3 = new Double(3.2);
Double db4 = new Double(3.2);
System.out.println("Double db3 = new Double(3.2),Double db4 = new Double(3.2) db3==db4的结果为:"+(db3==db4));
}
}
运行结果:
Integer ig1 = 3,Integer ig2 = 3 ig1==ig2的结果为:true
Integer ig3 = new Integer(3),Long ig4 = new Integer(3) ig3==ig4的结果为:false
Long lg1 = 3l,Long lg2 = 3l lg1==lg2的结果为:true
Long lg3 = new Long(3),Long lg4 = new Long(3) lg3==lg4的结果为:false
Float flt1 = 3.2f,Float flt2 = 3.2f flt1==flt2的结果为:false
Float flt3 = new Float(3.2),Float flt4 = new Float(3.2)) flt3==flt4的结果为:false
Double db1 = 3.2,Double db2 = 3.2 db1==db2的结果为:false
Double db3 = new Double(3.2),Double db4 = new Double(3.2) db3==db4的结果为:false
从结果可以看出,只有Integer和Long类型直接赋数值的时候,使用“==”判断相等才会为true,其余的时候都为false。
也就是说其余的情况比较多都是变量在内存存放的地址,并不是变量的数值。
那为什么Integer和Long类型直接赋数值,结果为true,而Float和Double类型直接赋数值,结果为false呢?我猜测,Java本身有优化措施,就是给Integer和Long类型直接赋数值的时候,内存里面并没有建立Integer和Long类型的对象,而是直接优化为基本数据类型int和long,所以是用“==”判断相等,结果才会为true。
为了保险起见,当判断封装类变量的数值相等时,最好直接取出数值来进行“==”判断,或者使用equals方法,即
lg1.equals(lg2)
像这些小细节,如果不搞清楚,说不定什么时候就造成大麻烦。
细节决定成败,Java编程中还有很多需要注意的细节,这里只探讨一二。