技术开发 频道

实战 Groovy: for each 剖析

  Java 迭代策略

  假设您有一个 Java 编程语言的 java.util.List。清单 1 展示了在 Java 语言中如何使用编程实现迭代:

  清单 1. Java 列表迭代  

import java.util.*;

  
public class ListTest{

  
public static void main(String[] args){

  List list
= new ArrayList();

  list.add(
"Java");

  list.add(
"Groovy");

  list.add(
"JavaScript");

  
for(Iterator i = list.iterator(); i.hasNext();){

  
String language = i.next();

  System.out.println(
"I know " + language);

  }

  }

  }

  由于提供了大部分集合类都可以共享的 java.lang.Iterable 接口,您可以使用相同的方法遍历 java.util.Set 或 java.util.Queue。

  现在,假设该语言存储在 java.util.Map 中。在编译时,尝试对 Map 获取 Iterator 会导致失败 — Map 并没有实现 Iterable 接口。幸运的是,可以调用 map.keySet() 返回一个 Set,然后就可以继续处理。这些小差异可能会影响您的速度,但不会妨碍您的前进。需要注意的是,List、Set 和 Queue 实现了 Iterable,但是 Map 没有 — 即使它们位于相同的 java.util 包中。

  现在假设该语言存在于 String 数组中。数组是一种数据结构,而不是类。不能对 String 数组调用 .iterator(),因此必须使用稍微不同的迭代策略。您再一次受到阻碍,但可以使用如清单 2 所示的方法解决问题:

  清单 2. Java 数组迭代  

public class ArrayTest{

  
public static void main(String[] args){

  
String[] list = {"Java", "Groovy", "JavaScript"};

  
for(int i = 0; i < list.length; i++){

  
String language = list[i];

  System.out.println(
"I know " + language);

  }

  }

  }

  但是等一下 — 使用 Java 5 引入的 for-each 语法怎么样(参见 参考资料)?它可以处理任何实现 Iterable 的类和数组,如清单 3 所示:

  清单 3. Java 语言的 for-each 迭代  

import java.util.*;

  
public class MixedTest{

  
public static void main(String[] args){

  List list
= new ArrayList();

  list.add(
"Java");

  list.add(
"Groovy");

  list.add(
"JavaScript");

  
for(String language: list){

  System.out.println(
"I know " + language);

  }

  
String[] list2 = {"Java", "Groovy", "JavaScript"};

  
for(String language: list2){

  System.out.println(
"I know " + language);

  }

  }

  }

  因此,您可以使用相同的方法遍历数组和集合(Map 除外)。但是如果语言存储在 java.io.File,那该怎么办?如果存储在 JDBC ResultSet,或者存储在 XML 文档、java.util.StringTokenizer 中呢?面对每一种情况,必须使用一种稍有不同的迭代策略。这样做并不是有什么特殊目的 — 而是因为不同的 API 是由不同的开发人员在不同的时期开发的 — 但事实是,您必须了解 6 个 Java 迭代策略,特别是使用这些策略的特殊情况。

  Eric S. Raymond 在他的 The Art of Unix Programming(参见 参考资料)一书中解释了 “最少意外原则”。他写道,“要设计可用的接口,最好不要设计全新的接口模型。新鲜的东西总是难以入门;会为用户带来学习的负担,因此应当尽量减少新内容。”Groovy 对迭代的态度正是采纳了 Raymond 的观点。在 Groovy 中遍历几乎任何结构时,您只需要使用 each() 这一种方法。

0
相关文章