摘 要:Java平台提供了多种方式遍历对象的集合,其中包括今年3月19日发布的Java 8中引入的新特性。本文回顾了迭代器,着重分析了主动式迭代器和被动式迭代器之间的差异,研究了Java 8的foreach()方法和Stream API如何改进和并行化Java迭代器的行为,然后对主动迭代、流和并行流这三种方法进行了性能比较。总之,Java 8的迭代器可读性更好,不易出错,也更容易并行化。 关键词:Java8;集合;迭代器 中图分类号:TP311 文献标识码:A 1 引言(Introduction) 在编程世界里一般需要提供一种机制遍历软件对象的集合。大多数编程语言都有类似于数组的功能并且直接支持数组元素的遍历,但是现代的编程语言还支持更为复杂的数据结构,如列表、集合、映射和树,遍历能力是通过公共方法提供,而内部细节都隐藏在类的私有部分,所以程序员不需要了解其内部实现就能够遍历这些数据结构中的元素,这就是迭代的目的。 迭代器是对集合中的所有元素进行顺序访问并可以对每个元素执行某些操作的机制。迭代器在本质上提供了在封装的对象集合上做“循环”的装置。常见的使用迭代器的例子有: 访问目录中的每个文件并显示文件名;访问队列中的每个客户(如银行排队)并判断他或她等待了多久。使用迭代器时,一般情况下可以循环嵌套,即可以在同一时间做多个遍历;迭代器应该是无损的,即迭代行为不应该改变集合本身,如迭代时不要从集合中移除或插入元素;在某些情况下你还需要使用迭代器的不同的遍历方法,例如,树的前序遍历和后序遍历,或者深度优先和广度优先遍历。 根据Gang of Four,迭代器设计模式是一种行为模式,其核心思想是负责访问和遍历列表中的对象,并把这些对象放到一个迭代器对象中[1]。迭代器的实现方法根据谁来控制迭代分为两种:主动迭代和被动迭代。主动迭代器是由客户程序创建迭代器,调用next()行进到下一个元素,测试查看是否所有元素已被访问等等,总之客户程序是可以操作的。这种方法在象C++这样的语言中最为常见,在GoF的书中也是最为关注的方法,主动迭代器在Java 8之前可以说是Java的唯一选择。被动迭代器则是迭代器本身控制迭代,即迭代器自行next()向下走,针对客户程序来说迭代是透明的,是不能操作的。这种方法在象LISP这样的语言中很常见。随着Java 8的发布,这种迭代方法也成为Java程序员的一个选择。 2 Java 8之前的迭代(Iteration before Java 8) 为了说明Java中的各种迭代方法,我们需要一个集合并对集合中的元素做些操作,本文选择代表事物或人物名称的字符串的集合,我们将简单地打印集合中的每个名称到标准输出。这些基本的思想很容易扩展到更为复杂的对象的集合(如员工),并在处理每一个对象的时候可以涉及更为复杂的操作。 在Java 1.0和1.1中两个主要的集合类是Vector(向量)和Hashtable(哈希表),迭代器是通过一个叫做Enumeration(枚举)的类实现的。今天无论是Vector还是Hashtable都是泛型类,但退回到那时泛型还不是Java语言的一部分。代码清单1演示了使用枚举来处理字符串向量的方法。 Vector names = new Vector(); names.add("Apple"); names.add("Orange"); Enumeration e = names.elements(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); System.out.println(name); } |