JAVA中的foreach和迭代器

foreach语法主要运用于数组,但它也同样可以应用于任何一个Collection对象,看下面一段代码:

package access;
import java.util.*;
public class ForEachCollections {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Collection<String> cs = new LinkedList<String>();
		Collections.addAll(cs, "It is too hard".split(" "));
		for(String s : cs)
			System.out.print("'" + s + "'");
	}

}
此程序的输出结果为:


cs是一个Collection,能够与foreach一起工作的是所有Collection对象的特性。

之所以它能够工作,是因为引入了Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,并且iterable被foreach用来在序列中移动,如果我们创建了任何实现Iterable的类,都可以应用于foreach当中,看如下一段代码:

package access;
import java.util.*;
public class IterableClass implements Iterable<String>{
	protected String[] words =("And that is how "
			+ "we know the Earth to be banana-shaped.").split(" ");
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(String s : new IterableClass())
			System.out.print(s + " ");
	}

	@Override
	public Iterator<String> iterator() {
		// TODO Auto-generated method stub
		return new Iterator<String>(){
			private int index = 0;
			public boolean hasNext(){
				return index < words.length;
			}
			public String next(){
				return words[index++];
			}
			
		};
	}

}
此程序的输出结果为:


此例子中包含了一个匿名内部类,该内部类实现了Iterator<String>,用于遍历数组中的所有单词,在main中可以看到IterableClass确实用于foreach中,在foreach循环的过程中,由于IterableClass继承自Itrable接口,所以必须实现Itrable接口的Iterator方法,该方法的实现放在内部类中。通过foreach的循环操作以及Iterator内部实现的方法的被调用实现了数组的遍历。

在后续的JAVA版本中,大量的类都是Iterable类型,主要包括Collection类,但不包括Map,看如下一段代码:

package access;
import java.util.*;
public class EnvironmentVariables {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(Map.Entry entry : System.getenv().entrySet()){
			System.out.println(entry.getKey() + ": " + entry.getValue());
		}
	}

}
该例子用于产生所有系统环境变量。

System.getenv方法用于产生系统变量并以Map的形式返回。

entrySet方法将产生一个由Map.Entry元素构成的Set,所以实际上在foreach中循环的是Set并非Map。
foreach可以运用于数组,但数组并不是Iterable,看如下一段代码:

package access;
import java.util.*;
public class ArrayIsNotIterable {
	static <T> void test(Iterable<T> ib){
		for(T t : ib)
			System.out.print	(t + " ");
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		test(Arrays.asList(1,2,3));
		String[] strings = {"A","B","C"};
		//test(strings);
		test(Arrays.asList(strings));
	}

}
此程序的输出结果为:


当把数组当作Iterable参数传递会导致失败,不存在数组到Iterable的自动转换,我们只能通过手工转化。

如果我们希望可以选择向前或向后的方向迭代一个单词列表,如果直接继承类,那么我们只能替换现有的方法,不能实现选择,我们可以采用适配器方法,适配器部分来自于设计模式,我们必须提供特定的接口满足foreach语句,可以通过添加一个能够产生iterable对象的方法,该对象可以用于foreach。看如下代码:

package access;
import java.util.*;
public class MultiIterableClass extends IterableClass{
	public Iterable<String> reversed(){
		return new Iterable<String>(){
			public Iterator<String> iterator(){
				return new Iterator<String>(){
					int current = words.length - 1;
					public boolean hasNext(){
						return current > -1;
					}
					public String next(){
						return words[current--];
					}
				};
			}
		};
		
	}
	public Iterable<String> randomized(){
		return new Iterable<String>(){

			@Override
			public Iterator<String> iterator() {
				// TODO Auto-generated method stub
				List<String> shuffled = 
						new ArrayList<String>(Arrays.asList(words));
				Collections.shuffle(shuffled,new Random(40));
				return shuffled.iterator();
			}
		};
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MultiIterableClass mic = new MultiIterableClass();
		for(String s : mic.reversed())
			System.out.print(s + " ");
		System.out.println();
		for(String s : mic.randomized())
			System.out.print(s + " ");
		System.out.println();
		for(String s : mic)
			System.out.print(s + " ");
	}

}
此程序的输出结果为:


上述程序中多次运用了匿名内部类来实现。

第二个方法random并没有创建自己的Iterator,直接返回了被打乱的List的Iterator,Collection.shuffle方法并没有影响到原来的数组,而是打乱了shuffled的引用,因为其创建了一个ArrayList,如果由Arrays.asList方法产生的List直接被打乱,则会彻底打乱数组,如以下一段代码:

package access;
import java.util.*;
public class ModifyingArrayAsList {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Random rand = new Random(40);
		Integer[] ia = {1,2,3,4,5,6,7,8,9,10};
		List<Integer> list1 = 
				new ArrayList<Integer>(Arrays.asList(ia));
		System.out.println("Before shuffling: " + list1);
		Collections.shuffle(list1,rand);
		System.out.println("After shuffling: " + list1);
		System.out.println("array: " + Arrays.toString(ia));
		System.out.println();
		List<Integer> list2 = Arrays.asList(ia);
		System.out.println("Before shuffling: " + list2);
		Collections.shuffle(list2,rand);
		System.out.println("After shuffling: " + list2);
		System.out.println("array: " + Arrays.toString(ia));
	}

}
此程序的输出结果为:


如果我们执行的操作会修改这个List,但我们并不想这个List本身被修改的情况下,我们应该创建一个副本来进行操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值