对于我们常用的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的更多相关文章

  1. Java暗箱操作之enum

    enum,即枚举类型,在每种编程语言中都有类似的类型. 因为用得少,语法规则很难记得住,我每次看到enum都会感到害怕. 一般的enum语法是这样的: public class MyClass { p ...

  2. Java暗箱操作之自动装箱与拆箱

    我以前在写Android项目的时候,估计写得最多最熟练的几句话就是: List<Integer> list = new ArrayList<Integer>(); list.a ...

  3. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  4. 给Java开发人员的Play Framework(2.4)介绍 Part1:Play的优缺点以及适用场景

    1. 关于这篇系列 这篇系列不是Play框架的Hello World,由于这样的文章网上已经有非常多. 这篇系列会首先结合实际代码介绍Play的特点以及适用场景.然后会有几篇文章介绍Play与Spri ...

  5. Java虚拟机的内存管理

    众所周知,Java程序员写的代码是没有办法控制Java对象的内存释放的,完全有JVM暗箱操作. 虽然程序员把内存的释放的任务都交给了Java虚拟机,但是并不代表Java程序就不存在内存泄漏. 反而,某 ...

  6. 【Java技术系列】爱情36技之追美妹的技术

    1. 在古老的非洲大陆上,有个原始人无意中抬头仰望星空,凝视的时间稍微长了一些,超过了外星人设置的阈值,立刻拉响了人类即将产生文明的警报.因为外星人认为,人类已经产生了对宇宙的好奇心,文明的产生,科技 ...

  7. 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题

    背景起因: 记起以前的另一次也是关于内存的调优分享下   有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...

  8. Elasticsearch之java的基本操作一

    摘要   接触ElasticSearch已经有一段了.在这期间,遇到很多问题,但在最后自己的不断探索下解决了这些问题.看到网上或多或少的都有一些介绍ElasticSearch相关知识的文档,但个人觉得 ...

  9. 论:开发者信仰之“天下IT是一家“(Java .NET篇)

    比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...

随机推荐

  1. 【记录】ASP.NET MVC 4/5 Authentication 身份验证无效

    在 ASP.NET MVC 4/5 应用程序发布的时候,遇到一个问题,在本应用程序中进行身份验证是可以,但不能和其他"二级域名"共享,在其他应用程序身份验证,不能和本应用程序共享, ...

  2. mysql表名查询sql

    select table_schema,table_name,engine from information_schema.tables where table_schema not in('info ...

  3. Windows Server 2008 R2 添加且制成“NFS服务器”角色后与Unix客户端匿名访问常见问题

    在复杂的主机与网络环境中,我们可能会接触到多种主机与操作系统,配合Windows Server 2008 R2的原生“NFS服务器”功能可以让这样的复杂操作系统更方便应用. 然而面对网络上众多的帮助指 ...

  4. 微信公众平台开发(二)——access_token、日志

    一.access_token 1)两种access_token,网页授权access_token和普通access_token 1.微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后, ...

  5. 深入seajs源码系列三

    入口方法 每个程序都有个入口方法,类似于c的main函数,seajs也不例外.系列一的demo在首页使用了seajs.use(),这便是入口方法.入口方法可以接受2个参数,第一个参数为模块名称,第二个 ...

  6. Fragment基础----信息传递

    如何通过activity来访问fragment的信息呢,我们可以通过一个实例来了解. 使用两个Fragment和一个activity管理 效果图: 第一个fragment来表示输入框 第二个fragm ...

  7. 数据库join方式分析

    前言    不管是博客园还是CSDN,看到很多朋友对数据库的理解.认识还是没有突破一个瓶颈 ,而这个瓶颈往往只是一层窗纸,越过了你将看到一个新世界.    04.05年做项目的时候,用SQL Serv ...

  8. Azure Media Service (1) 使用OBS进行Azure Media Service直播

    <Windows Azure Platform 系列文章目录> 今天正好有客户问如何使用OBS进行Azure Media Service直播,我这里简单介绍一下. 先决条件: 1. OBS ...

  9. MySQL一个语句查出各种整形占用字节数及最大最小值

    直接上码: as min_num union , union , union , union , union ,) union ,) union ,) union ,) union ,); +---- ...

  10. Keil环境中建立带FreeRTOS的STM32L项目

    本文是网上转载,版权所有. Keil环境中建立带FreeRTOS的STM32L项目 1.先把source文件夹复制至project目录,然后在keil中添加RTOS文件,如图: 其中heap_2.c按 ...