Java暗箱操作之for-each
对于我们常用的ArrayList等容器类,经常需要一个一个遍历里面的元素,从而对各个元素执行对应的操作。
像我代码写多了,通常的做法是用传统的,类似于数组遍历的方法,即在for循环中设置一个int变量作为索引,然后用List的get方法,想怎么做就怎么做,不会遇到任何不能做的事。
当然,偶尔我会写得简单一点,用 for (元素类型 变量名 :集合) 的方法,即不用索引,直接指定实际的元素类型,取下一个元素,这样可以少写一行代码。
但不管用哪一种,我都没有考虑过用迭代器iterator,虽然教程上面经常提到这东西,我也知道这是用来遍历,顺便执行删除等操作的。因为用类似数组遍历的方法取元素从未遇到过瓶颈,就从来没研究过iterator,也一直都觉得这是个没有卵用的东西。
最近在研究ArrayList和LinkedList源码的时候,源码里面也有很大一段是关于Iterator的,这让我更加不解了:既然是一个可有可无可替代的东西,为什么官方还要费这么大的劲来描述它呢?
直到最近阅读《Effective Java》,看了一节关于for-each和传统for循环的比较,里面有一句话让我重新审视Iterator:
Not only does the for-each loop let you iterate over collections and arrays,
it lets you iterate over any object that implements the Iterable interface.
这就不得不让我怀疑:难道我以前所知道的集合类,就是因为实现了Iterable接口,才可以用for加冒号的方式?
google了一下,果然,for-each这样一种简洁的书写方式,内部居然就是用迭代器实现的!
下面的代码摘自StackOverFlow
List<String> someList = new ArrayList<String>();
正常的用for-each遍历方法:
for (String item : someList) {
System.out.println(item);
}
重点来了,上面这简单的一句话,在编译过程中,被编译器自动翻译成了下面这段,真正执行的时候也正是下面这段:
for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
String item = i.next();
System.out.println(item);
}
所以,在实际开发中,虽然明面上很少用到标标准准的Iterator,但是常用的for-each的暗箱操作却都是Iterator!
Java创造出来for-each的操作,好处之一当然是简化了代码的书写,减少了变量个数。
另外还有很重要的一点是大大降低了遍历过程当中的误操作。想想看,如果在for-each过程中,你得到了当前位置的元素值,有什么办法可以添加、删除或修改元素值呢?答案是没有。然而利用Iterator或者索引来写循环,你可以进行几乎所有的增删改操作。所以利用for-each来操作更安全。
当然,for-each还有一种用法,即用在普通数组的遍历当中,当中也进行了暗箱操作,即转换为索引的遍历。
int[] test = new int[] {1,4,5,7}; for (int intValue : test) {
// do some work here on intValue
}
编译时转换为:
int[] test = new int[] {1,4,5,7}; for (int i = 0; i < test.length; i++) {
int intValue = test[i];
// do some work here on intValue
}
一定要注意,for-each只能用于:①Iterable ②数组
也即,除了数组以外,一般的类只要实现了Iterable接口就能用for-each
我们可以随便写个类玩玩。
import java.util.Iterator; public class MyClass<E> implements Iterable<E>{ private class MyIterator implements Iterator<E> { private int max = 10;
private int cur = 0; @Override
public boolean hasNext() {
if (cur < max)
return true;
else
return false;
} @SuppressWarnings("unchecked")
@Override
public E next() {
Object res = ++cur;
return (E) res;
} @Override
public void remove() {
System.out.println("索引:"+cur+" 被删除");
} }; @Override
public Iterator<E> iterator() {
return new MyIterator();
} }
测试下
import java.util.Iterator; public class JavaMain { public static void main(String[] args) {
MyClass<Integer> m = new MyClass<>();
for (Integer i : m) {
System.out.println(i);
}
System.out.println("-------------------------------------------");
for (Iterator<Integer> it = m.iterator();it.hasNext();) {
Integer val = it.next();
if (val % 3 == 0)
it.remove();
}
} }
输出结果:
1
2
3
4
5
6
7
8
9
10
-------------------------------------------
索引:3 被删除
索引:6 被删除
索引:9 被删除
我们这里的MyClass类没有任何实际的意义,居然试验成功了,真是一件不可思议的事情。。。
参考资料:
http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work
http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2
Java暗箱操作之for-each的更多相关文章
- Java暗箱操作之enum
enum,即枚举类型,在每种编程语言中都有类似的类型. 因为用得少,语法规则很难记得住,我每次看到enum都会感到害怕. 一般的enum语法是这样的: public class MyClass { p ...
- Java暗箱操作之自动装箱与拆箱
我以前在写Android项目的时候,估计写得最多最熟练的几句话就是: List<Integer> list = new ArrayList<Integer>(); list.a ...
- Spark案例分析
一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...
- 给Java开发人员的Play Framework(2.4)介绍 Part1:Play的优缺点以及适用场景
1. 关于这篇系列 这篇系列不是Play框架的Hello World,由于这样的文章网上已经有非常多. 这篇系列会首先结合实际代码介绍Play的特点以及适用场景.然后会有几篇文章介绍Play与Spri ...
- Java虚拟机的内存管理
众所周知,Java程序员写的代码是没有办法控制Java对象的内存释放的,完全有JVM暗箱操作. 虽然程序员把内存的释放的任务都交给了Java虚拟机,但是并不代表Java程序就不存在内存泄漏. 反而,某 ...
- 【Java技术系列】爱情36技之追美妹的技术
1. 在古老的非洲大陆上,有个原始人无意中抬头仰望星空,凝视的时间稍微长了一些,超过了外星人设置的阈值,立刻拉响了人类即将产生文明的警报.因为外星人认为,人类已经产生了对宇宙的好奇心,文明的产生,科技 ...
- 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题
背景起因: 记起以前的另一次也是关于内存的调优分享下 有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...
- Elasticsearch之java的基本操作一
摘要 接触ElasticSearch已经有一段了.在这期间,遇到很多问题,但在最后自己的不断探索下解决了这些问题.看到网上或多或少的都有一些介绍ElasticSearch相关知识的文档,但个人觉得 ...
- 论:开发者信仰之“天下IT是一家“(Java .NET篇)
比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...
随机推荐
- 【记录】ASP.NET MVC 4/5 Authentication 身份验证无效
在 ASP.NET MVC 4/5 应用程序发布的时候,遇到一个问题,在本应用程序中进行身份验证是可以,但不能和其他"二级域名"共享,在其他应用程序身份验证,不能和本应用程序共享, ...
- mysql表名查询sql
select table_schema,table_name,engine from information_schema.tables where table_schema not in('info ...
- Windows Server 2008 R2 添加且制成“NFS服务器”角色后与Unix客户端匿名访问常见问题
在复杂的主机与网络环境中,我们可能会接触到多种主机与操作系统,配合Windows Server 2008 R2的原生“NFS服务器”功能可以让这样的复杂操作系统更方便应用. 然而面对网络上众多的帮助指 ...
- 微信公众平台开发(二)——access_token、日志
一.access_token 1)两种access_token,网页授权access_token和普通access_token 1.微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后, ...
- 深入seajs源码系列三
入口方法 每个程序都有个入口方法,类似于c的main函数,seajs也不例外.系列一的demo在首页使用了seajs.use(),这便是入口方法.入口方法可以接受2个参数,第一个参数为模块名称,第二个 ...
- Fragment基础----信息传递
如何通过activity来访问fragment的信息呢,我们可以通过一个实例来了解. 使用两个Fragment和一个activity管理 效果图: 第一个fragment来表示输入框 第二个fragm ...
- 数据库join方式分析
前言 不管是博客园还是CSDN,看到很多朋友对数据库的理解.认识还是没有突破一个瓶颈 ,而这个瓶颈往往只是一层窗纸,越过了你将看到一个新世界. 04.05年做项目的时候,用SQL Serv ...
- Azure Media Service (1) 使用OBS进行Azure Media Service直播
<Windows Azure Platform 系列文章目录> 今天正好有客户问如何使用OBS进行Azure Media Service直播,我这里简单介绍一下. 先决条件: 1. OBS ...
- MySQL一个语句查出各种整形占用字节数及最大最小值
直接上码: as min_num union , union , union , union , union ,) union ,) union ,) union ,) union ,); +---- ...
- Keil环境中建立带FreeRTOS的STM32L项目
本文是网上转载,版权所有. Keil环境中建立带FreeRTOS的STM32L项目 1.先把source文件夹复制至project目录,然后在keil中添加RTOS文件,如图: 其中heap_2.c按 ...