乐趣区

foreach写失效的问题

本文由作者张远道授权网易云社区发布。
坦白讲身为程序员,bug 在所难免。有人讲,bug 越多,说明程序员越伟大。这句话有它一定的道理。
因为从某方面讲,bug 多了说明他的代码量也多。
言归正传,这里我记录了我曾经犯过的几个错误。希望看到的同侪能够见而避之。
常用的一个场景,遍历一个集合,对符合某种条件的元素做修改。习惯性地会写出如下代码:
List testInt = new ArrayList();
testInt.add(1);
testInt.add(2);
testInt.add(3); for(Integer temp :testInt){if(temp==1)
temp=temp*2;
}
for(Integer a:testInt){
System.err.println(a);
}

期待的结果是:
2
2
3
但实际输出为:
1
2
3
这是很容易掉进去的陷阱。即通过 foreach 遍历对集合元素进行修改。在以为变更已发生的时候,
其实变更没有发生。造成数据写入失败。
因为
for(Integer temp:testInt){if(temp==1)
temp=temp*2;
}

将被翻译成
for(int i=0,length=testStr.size();i<length;i++){

Integer temp = testStr.get(i).clone();

if(temp==1)

temp=temp*2;

}

根据 oracle 的官方文档, 正式翻译应该如下
for (Iteratori = testInt.iterator(); i.hasNext();) {float i0 = (Integer)i.next(); if(i0 == 1)
i0 = i0*2;
}

即,foreach 里头的的 temp 变量只是一个局部变量,而且还是集合中元素的一个副本,并不是元素本身。
想到之前还遇到的一个问题,代码简化如下:
Integer integer1 = 3;
Integer integer2 = 3; if (integer1 == integer2)
System.out.println(“integer1 == integer2”); else
System.out.println(“integer1 != integer2”);

Integer integer3 = 300;
Integer integer4 = 300;
if (integer3 == integer4)
System.out.println(“integer3 == integer4”); else
System.out.println(“integer3 != integer4”);

即在判断整数相等时, 使用了封装类 (由数据库映射过来,用封装类防止反射异常)。实际的输出结果如下:
integer1 == integer2
integer3 != integer4
明眼人很容易看出来,这里掉入了两个坑. 一个坑是用等号判断相等, 除非是为了比较同一个对象,等值比较不应该直接用等号。另一个坑是
java 的整数缓存。
查看 jdk 的源码如下:
private static class IntegerCache {static final int low = -128; static final int high; static final Integer cache[]; static {// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”); if (integerCacheHighPropValue != null) {int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE – (-low));
}
high = h;

cache = new Integer[(high – low) + 1]; int j = low; for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
} private IntegerCache() {}
}

即整数缓存缓存了前 127 个整数,没有重新生成。
当然,还遇到其它各种各样的坑。可怕的不是掉入坑中,而是掉入坑里了不正视问题也不查找问题所在,一而再再而三地掉进坑里。
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请访问网易云社区。
文章来源:网易云社区

退出移动版