本文由ImportNew-liqing翻译自javarevisited。欢迎加入Java小组。转载请参见文章末尾的要求。
从Java5起,在Java中有了for-each循环,可以用来循环遍历collection和array。For each循环允许你在无需保持传统for循环中的索引,或在使用iterator /ListIterator时无需调用while循环中的hasNext()方法就能遍历collection。Java中,for-each循环简化了任何Collection或array的遍历过程,但并不是每个Java程序员都了解本文将要描述的for-each 循环的一些细节。与 Java5 发布的其他术语:释放别名泛型,自动封装和可变参数不同,Java开发者对for-each循环的使用比任何其他特性更加频繁,但当问及高级的for-each循环怎样工作,或什么是在for-each循环中使用Collection时的基本需求时,就不是每个人都能够回答的了。本篇教程和例子旨在通过深入研究for-each
循环中几个有趣的难题来填补上述空白(说明上述问题)。好了,不再赘述,一起看看我们在Java5 for-each循环的第一个问题。
高级循环问题 1
考虑下面这段遍历一个用户自定义的aggregator或collection类的代码,这段代码将会打印出什么,抛出异常还是编译器错误:
package test;
/**
* Java Class to show how for-each loop works in Java
*/
public class ForEachTest {
public static void main(String args[]){
CustomCollection<String> myCollection = new CustomCollection<String>();
myCollection.add("Java");
myCollection.add("Scala");
myCollection.add("Groovy");
//What does this code will do, print language, throw exception or compile time error
for(String language: myCollection){
System.out.println(language);
}
}
}
下面是我们的CustomCollection类,这是个参数为泛型的类,与任何其他的Collection类相似,依靠于ArrayList并提供从Collection中添加和删除项的方法。
package test;
public class CustomCollection<T>{
private ArrayList<T> bucket;
public CustomCollection(){
bucket = new ArrayList();
}
public int size() {
return bucket.size();
}
public boolean isEmpty() {
return bucket.isEmpty();
}
public boolean contains(T o) {
return bucket.contains(o);
}
public boolean add(T e) {
return bucket.add(e);
}
public boolean remove(T o) {
return bucket.remove(o);
}
}
上述代码将无法通过编译,这是因为我们的CustomCollection类没有实现java.lang.Iterable接口,编译期错误如下:
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - for-each not applicable to expression type
required: array or java.lang.Iterable
found: test.CustomCollection
at test.ForEachTest.main(ForEachTest.java:24)
从中了解到的一个有趣的事实是:for-each循环仅应用于实现了Iterable接口的Java array和Collection类,而且既然所有内置Collection类都实现了java.util.Collection接口,已经继承了Iterable,这一细节通常会被忽略,这点可以在Collection接口的类型声明“
public interface Collection extends Iterable”中看到。所以为了解决上述问题,你可以选择简单地让CustomCollection实现Collection接口或者继承AbstractCollection,这是默认的通用实现并展示了如何同时使用抽象类和接口以获取更好的灵活性。现在让我们来看看for-each循环的第二个难题:
Java for-each循环的第二个难题:
在下面的代码示例将会抛出ConcurrentModificationException异常。这里我们使用标准iterator和for-each循环遍历ArrayList,随后删除元素,你需要找出哪段代码将会抛出ConcurrentModificationException ,为什么?请注意,答案可能是两个都会,都不会或其中之一。
packagetest;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.Iterator;
/**
* Java class to demonstrate inner working of for-each loop in Java
* @author Javin Paul
**/
publicclassForEachTest2 {
publicstaticvoid main(String args[]){
Collection<String> list = newArrayList<String>();
list.add("Android");
list.add("iPhone");
list.add("Windows Mobile");
// Which Code will throw ConcurrentModificationException, both,
// none or one of them
// example 1
Iterator<String> itr = list.iterator();
while(itr.hasNext()){
String lang = itr.next();
list.remove(lang);
}
// example 2
for(String language: list){
list.remove(language);
}
}
}
大约70%的Java开发者都会说第一个代码块会抛出ConcurrentModificationException异常,因为我们没有用iterator的remove方法来删除元素,而是使用ArrayList的 remove()方法。但是,没有多少Java开发者会说出for-each循环也会出现同样的问题,因为我们在这里没有使用iterator。事实上,第二个代码片段也会抛出ConcurrentModificationException异常,这点在解决了第一个困惑之后就变得很明显了。既然for-each循环内部使用了Iterator来遍历Collection,它也调用了Iterator.next(),这会检查(元素的)变化并抛出ConcurrentModificationException。你可以从下面的输出中了解到这点,在注释掉第一个代码段后,当你运行第二个代码段时会得到下面的输出。
Exceptioninthread"main"java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
attest.ForEachTest2.main(ForEachTest2.java:34)
译者注:语法糖(syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达-Peter J. Landin发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
原文链接:javarevisited翻译:ImportNew.com-liqing
译文链接:http://www.importnew.com/11038.html
[转载请保留原文出处、译者和译文链接。]
分享到:
相关推荐
MATLAB工具箱大全-将多重循环转为单重循环-For-Each
从Java5起,在Java中有了for-each循环,可以用来循环遍历collection和array。For each循环允许你在无需保持传统for循环中的索引,或在使用iterator /ListIterator时无需调用while循环中的hasNext()方法就能遍历...
下面是用一个传统的for循环遍历集合的例子:用传统的for循环遍历数组的做法如下:这些做法逗比while循环更好,但是它们并不完美。如果真的那么不幸,并且外部集
本文详解了JAVA中的for-each循环与迭代,是JS入门学习中的基础知识,也是java中的难点知识,需要的朋友可以参考下 。
22 For-Each 23 PlotPub 24 Sheffield大学最新遗传算法工具箱 25 Camera Calibration 像机标定工具箱 26 Qhull(二维三维三角分解、泰森图)凸包工具箱 2019版 27 jplv7 28 MatlabFns 29 张量工具箱Tensor Toolbox 30 ...
VB For each循环实例 VB For each循环实例
java1.7-part1
Java for循环类For循环上的Java分配使用“ for”循环计数到100给定一个主要功能: int lastNumber = 100 ;System . out . println( " Starting Count to " + lastNumber);countTheNumbers(lastNumber); 创建一个...
Java for循环类For循环上的Java分配使用“ for”循环计数到100给定一个主要功能: int lastNumber = 100 ;System . out . println( " Starting Count to " + lastNumber);countTheNumbers(lastNumber); 创建一个...
var forEach = require ( "for-each" ) forEach ( { key : "value" } , function ( value , key , object ) { /* code */ } ) 另外,它也是阵列的完美功能填充/填充! var forEach = require ( "for-each" ) ...
全面、准确、详尽地介绍了Java语言及其语法,论述了Java编译器所要检查的语法和Java运行模式的各个方面,同时还描述了Java语盲最重要的新特征(包括generics、annotationS、aSSertS、autoboxing、enumS、for-...
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
[微笔记]Houdini For-each迭代小案例-附件资源
jQuery-each用法全面总结,分门别类,有说明,有举例。
for_each 返回值实例详解;
$ npm install p-each-series 用法 import pEachSeries from 'p-each-series' ; const keywords = [ getTopKeyword ( ) , //=> Promise 'rainbow' , 'pony' ] ; const iterator = async element => ...
它提供了对于自前一版以来添加的所有新特性的完整描述,包括泛型、注释、断言、自动装臬、枚举、for-each循环、可变元数方法和静态导入子句。 本书试图详细说明Java语言的语法和语义规范。编者试图在每一种语言结构...
从Jest> = 23开始, jest-each本身可与test.each和describe.each一起test.each , 如果您使用的是旧版本的Jest,我仍会在核心存储库中维护jest-each ,因此您仍然可以按照与正常情况完全相同的方式使用jest-each :...