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个整数,没有重新生成。
当然,还遇到其它各种各样的坑。可怕的不是掉入坑中,而是掉入坑里了不正视问题也不查找问题所在,一而再再而三地掉进坑里。
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请访问网易云社区。
相关文章:
【推荐】 从加班论客户端开发中的建模
foreach写失效的问题的更多相关文章
- 【Java学习笔记之十】Java中循环语句foreach使用总结及foreach写法失效的问题
foreach语句使用总结 增强for(part1:part2){part3}; part2中是一个数组对象,或者是带有泛性的集合. part1定义了一个局部变量,这个局部变量的类型与part2中的对 ...
- mybatis的foreach写用法
一.mybatis查询 public abstract List<Model> findByIds(@Param("ids")List<Integer> i ...
- 20162330 第三周 蓝墨云班课 泛型类-Bag 练习
目录 题目及要求 思路分析 遇到的问题和解决过程 代码实现及托管链接 感想 参考资料 题目及要求 代码运行在命令行中,路径要体现学号信息,IDEA中,伪代码要体现个人学号信息: 参见Bag的UML图, ...
- cache写策略
cache写策略 Write Through (完全写入) CPU向cache写入数据时,同时向memory也写一份,使cache和memory的数据保持一致.优点是简单,缺点是每次都要访问memor ...
- EffectiveC#11--选择foreach循环
1.C#的foreach语句可以为你的任何集合产生最好的迭代代码 不推荐如下写法(?原因未明白 作者意思是阻碍jit边界检测) int len = foo.Length; for ( int inde ...
- innodb 关键特性(两次写与自适应哈希索引)
两次写: 场景: 当发生数据库宕机时,可能innodb存储引擎正在写入某个页到表中,而这个页只写了一部分,这种情况被称为部分写失效,如果发生,可以通过重做日志进行恢复,重做日志中记录的是对页的物理操作 ...
- MySQL InnoDB特性:两次写(Double Write)
http://www.ywnds.com/?p=8334 一.经典Partial page write问题? 介绍double write之前我们有必要了解partial page write(部分页 ...
- InnoDB的关键特性-插入缓存,两次写,自适应hash索引
InnoDB存储引擎的关键特性包括插入缓冲.两次写(double write).自适应哈希索引(adaptive hash index).这些特性为InnoDB存储引擎带来了更好的性能和更高的可靠性. ...
- java 中,for、for-each、iterator 区别
java 中,for.for-each.iterator 区别: 无论是在数组中还是在集合中,for-Each加强型for循环都是它们各自的普通for循环的一种"简写方式",即两者 ...
随机推荐
- oracle pl/sql程序
简单的pl/sql程序 declare begin dbms_output.put_line('hello world'); end; 什么是PL/SQL? pl/sql(Procedure lang ...
- win7系统administrator用户提示没有管理员权限,造装驱动安装错误,软件无法使用
警告1909.无法创建快捷方式 最近使用windows 7 32位安装软件,好多都失败.出现以上类似错误. 解决方法:在系统盘(C:)右键属性“安全”选项卡--“编辑”,添加“Everyone”设置为 ...
- Tomcat端口被占用解决方法
端口被绑定,在命令提示符运行wmic process where "Caption='javaw.exe' and CommandLine like '%%bootstrap.jar%%'& ...
- linux 下安装gult
本文假设你之前没有用过任何任务脚本(task runner)和命令行工具,一步步教你上手Gulp.不要怕,它其实很简单,我会分为五步向你介绍gulp并帮助你完成一些惊人的事情.那就直接开始吧. 第一步 ...
- 04 存储库之mongodb
MongoDB 一 简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库1.易用性 MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库.不采用 ...
- 数据帮助类DBhelper的定义
数据库帮助类的使用DBhelperusing System;using System.Collections.Generic;using System.Text;using System.Data;u ...
- Spring Boot与Logback的运用(自定义异常+AOP)
在开发以及调试过程中,程序员对日志的需求是非常大的,出了什么问题,都要通过日志去进行排查,但是如果日志不清或者杂乱无章,则不利于维护 这边就比较详细的列举几种类型的日志,供大家参考 首先明白logba ...
- [转载红鱼儿]delphi 实现微信开发(2)接入微信公众号平台
先要学习一下接入的资料,在这里,因为原理都在,所以一定要认真阅读,然后,利用Delphi实现一个对应函数,然后申请微信公众平台接口测试帐号. function CheckSignature(const ...
- Linux下安装配置 Jdk1.6+Tomcat6+Apache2.2.x+jk_mod1.2 详解
本篇以Redhat AS5,内核为Linux 2.6.18-8.el5 为例,其中Redhat/Fedora系列基本一致,其他Linux或者版本均可以参考. STEP 1 软件下载:1. jdk1.6 ...
- storyBoard中取消键盘第一响应
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.view endEditing:YES]; } ...