关于java的java跳出for循环环问题

J2SE 1.5提供了另一种形式的for循环。借助这种形式的for循环,可以用更简单地方式来遍历数组和Collection等类型的对象。本文介绍使用这种循环的具体方式,说明如何自行定义能被这样遍历的类,并解释和这一机制的一些常见问题。在Java程序中,要&逐一处理&――或者说,&遍历&――某一个数组或Collection中的元素的时候,一般会使用一个for循环来实现(当然,用其它种类的循环也不是不可以,只是不知道是因为for这个词的长度比较短,还是因为for这个词的含义和这种操作比较配,在这种时候for循环比其它循环常用得多)。对于遍历数组,这个循环一般是采取这样的写法:清单1:遍历数组的传统方式
int[]&integers&=&{1,&2,&3,&4};&&
for&(int&j&=&0;&j&integers.&j++){&&
int&i&=&integers[j];&&
System.out.println(i);&&
而对于遍历Collection对象,这个循环则通常是采用这样的形式:清单2:遍历Collection对象的传统方式
String[]&strings&=&{"A",&"B",&"C",&"D"};&&
Collection&stringList&=&java.util.Arrays.asList(strings);&&
for&(Iterator&itr&=&stringList.iterator();&itr.hasNext();)&{&&
Object&str&=&itr.next();&&
System.out.println(str);&&
而在Java语言的最新版本――J2SE 1.5中,引入了另一种形式的for循环。借助这种形式的for循环,现在可以用一种更简单地方式来进行遍历的工作。1. 第二种for循环不严格的说,Java的第二种for循环基本是这样的格式:for (循环变量类型 循环变量名称 : 要被遍历的对象) 循环体借助这种语法,遍历一个数组的操作就可以采取这样的写法:清单3:遍历数组的简单方式
int[]&integers&=&{1,&2,&3,&4};&&
for&(int&i&:&integers)&{&&
System.out.println(i);
这里所用的for循环,会在编译期间被看成是这样的形式:清单4:遍历数组的简单方式的等价代码
int[]&integers&=&{1,&2,&3,&4};&&
for&(int&变量名甲&=&0;&变量名甲&integers.&变量名甲++)&{&&
System.out.println(integers[变量名甲]);
这里的&变量名甲&是一个由编译器自动生成的不会造成混乱的名字。而遍历一个Collection的操作也就可以采用这样的写法:清单5:遍历Collection的简单方式
String[]&strings&=&{"A",&"B",&"C",&"D"};&&
Collection&list&=&java.util.Arrays.asList(strings);&&
for&(Object&str&:&list)&{&&
System.out.println(str);
这里所用的for循环,则会在编译期间被看成是这样的形式:清单6:遍历Collection的简单方式的等价代码
String[]&strings&=&{"A",&"B",&"C",&"D"};&&
Collection&stringList&=&java.util.Arrays.asList(strings);&&
for&(Iterator&变量名乙&=&list.iterator();&变量名乙.hasNext();)&{&&
Object&str&=&变量名乙.next();&&
System.out.println(str);
这里的&变量名乙&也是一个由编译器自动生成的不会造成混乱的名字。因为在编译期间,J2SE 1.5的编译器会把这种形式的for循环,看成是对应的传统形式,所以不必担心出现性能方面的问题。不用&foreach&和&in&的原因Java采用&for&(而不是意义更明确的&foreach&)来引导这种一般被叫做&for-each循环&的循环,并使用&:&(而不是意义更明确的&in&)来分割循环变量名称和要被遍历的对象。这样作的主要原因,是为了避免因为引入新的关键字,造成兼容性方面的问题――在Java语言中,不允许把关键字当作变量名来使用,虽然使用&foreach&这名字的情况并不是非常多,但是&in&却是一个经常用来表示输入流的名字(例如java.lang.System类里,就有一个名字叫做&in&的static属性,表示&标准输入流&)。的确可以通过巧妙的设计语法,让关键字只在特定的上下文中有特殊的含义,来允许它们也作为普通的标识符来使用。不过这种会使语法变复杂的策略,并没有得到广泛的采用。&for-each循环&的悠久历史&for-each循环&并不是一个最近才出现的控制结构。在1979正式发布的Bourne shell(第一个成熟的UNIX命令解释器)里就已经包含了这种控制结构(循环用&for&和&in&来引导,循环体则用&do&和&done&来标识)。2. 防止在循环体里修改循环变量在默认情况下,编译器是允许在第二种for循环的循环体里,对循环变量重新赋值的。不过,因为这种做法对循环体外面的情况丝毫没有影响,又容易造成理解代码时的困难,所以一般并不推荐使用。Java提供了一种机制,可以在编译期间就把这样的操作封杀。具体的方法,是在循环变量类型前面加上一个&final&修饰符。这样一来,在循环体里对循环变量进行赋值,就会导致一个编译错误。借助这一机制,就可以有效的杜绝有意或无意的进行&在循环体里修改循环变量&的操作了。清单7:禁止重新赋值
int[]&integers&=&{1,&2,&3,&4};&&
for&(final&int&i&:&integers)&{&&
i&=&i&/&2;&
注意,这只是禁止了对循环变量进行重新赋值。给循环变量的属性赋值,或者调用能让循环变量的内容变化的方法,是不被禁止的。清单8:允许修改状态
Random[]&randoms&=&new&Random[]{new&Random(1),&new&Random(2),&new&Random(3)};&&
for&(final&Random&r&:&randoms)&{&&
r.setSeed(4);
System.out.println(r.nextLong());
3. 类型相容问题为了保证循环变量能在每次循环开始的时候,都被安全的赋值,J2SE 1.5对循环变量的类型有一定的限制。这些限制之下,循环变量的类型可以有这样一些选择:循环变量的类型可以和要被遍历的对象中的元素的类型相同。例如,用int型的循环变量来遍历一个int[]型的数组,用Object型的循环变量来遍历一个Collection等。清单9:使用和要被遍历的数组中的元素相同类型的循环变量
int[]&integers&=&{1,&2,&3,&4};&&
for&(int&i&:&integers)&{&&
System.out.println(i);
清单10:使用和要被遍历的Collection中的元素相同类型的循环变量
Collection&&String&&strings&=&new&ArrayList&&String&();&&
strings.add("A");&&
strings.add("B");&&
strings.add("C");&&
strings.add("D");&&
for&(String&str&:&integers)&{&&
System.out.println(str);
循环变量的类型可以是要被遍历的对象中的元素的上级类型。例如,用int型的循环变量来遍历一个byte[]型的数组,用Object型的循环变量来遍历一个Collection& String&(全部元素都是String的Collection)等。清单11:使用要被遍历的对象中的元素的上级类型的循环变量
String[]&strings&=&{"A",&"B",&"C",&"D"};&&
Collection&&String&&list&=&java.util.Arrays.asList(strings);&&
for&(Object&str&:&list)&{&&
System.out.println(str);
循环变量的类型可以和要被遍历的对象中的元素的类型之间存在能自动转换的关系。J2SE 1.5中包含了&Autoboxing/Auto-Unboxing&的机制,允许编译器在必要的时候,自动在基本类型和它们的包裹类(Wrapper Classes)之间进行转换。因此,用Integer型的循环变量来遍历一个int[]型的数组,或者用byte型的循环变量来遍历一个Collection& Byte&,也是可行的。清单12:使用能和要被遍历的对象中的元素的类型自动转换的类型的循环变量
int[]&integers&=&{1,&2,&3,&4};&&
for&(Integer&i&:&integers)&{&&
System.out.println(i);
注意,这里说的&元素的类型&,是由要被遍历的对象的决定的――如果它是一个Object[]型的数组,那么元素的类型就是Object,即使里面装的都是String对象也是如此。可以限定元素类型的Collection
截至到J2SE 1.4为止,始终无法在Java程序里限定Collection中所能保存的对象的类型――它们全部被看成是最一般的Object对象。一直到J2SE 1.5中,引入了&泛型(Generics)&机制之后,这个问题才得到了解决。现在可以用Collection& T&来表示全部元素类型都是T的Collection。
阅读(...) 评论()关于Java语言for循环内外变量定义的问题 - ITeye问答
今天被TeamLeader批了一顿,本来想和他争论争论的,后来感觉自己也不清楚,遂只有来Iteye讨教讨教了。
这是个关于在for循环内外变量定义的问题,先看代码:
public class Test2 {
public static void main(String[] args) {
// 放入的元素
List&Object& list = new ArrayList&Object&();
for(int i = 0; i & ; i++) {
list.add(i, new Object());
// 做10次循环,求均值
for(int j = 0; j & 10; j++) {
// 变量在循环内定义
long t1 = System.currentTimeMillis();
for(Iterator&Object& iterator = list.iterator(); iterator.hasNext();) {
Object object = iterator.next();
long t2 = System.currentTimeMillis();
System.out.println("循环内" + (j + 1) + "次, 时间:" + (t2 - t1) + ";");
// 变量在循环外定义
t1 = System.currentTimeMillis();
Object object =
for(Iterator&Object& iterator = list.iterator(); iterator.hasNext();) {
object = iterator.next();
t2 = System.currentTimeMillis();
System.out.println("循环外" + (j + 1) + "次, 时间:" + (t2 - t1) + ";");
/*其中一次的运行结果
变量在循环内定义 变量在循环外定义
我在工作中有一段代码是放到循环内定义的,主要是习惯,以及变量最小作用域的理念。但teamleader告诉我要放到循环外面,放在里面性能不好,不太理解。这个问题发生后,我也在网络寻找答案,但结果差不多一半一半,有建议在内部定义,也有建议在外部定义,所以就更糊涂了...我现在所知道的有:在内部定义,满足变量最小作用域的理念,循环外没有使用这个变量,该变量就不会在循环外定义;但teamleader说在内部定义会多次申请栈内存,影响性能,但我写了上面的例子和查了下资料,也没有弄太清这里面是如何影响性能的,请帮助详细讲解下两种定义方式的好坏,及其原因,和jdk版本是否有关系。
采纳的答案
从性能角度而言
引用teamleader说在内部定义会多次申请栈内存,影响性能,放在循环内部定义,确实会多次申请栈帧的内存空间(java中一个线程对应一个Java栈,每次方法调用会向栈中压入一个新帧,帧中存储着参数、局部变量、中间运算结果等等数据,方法调用结束后当前的帧就被弹出了,可参考我的一篇文章),为什么会多占用栈空间内,原因很简单,每次循环都要重复定义局部变量,而如果放在循环体外,每次只要移动引用指向的堆内存地址即可,不必重新申请内存空间了。
其实话说回来,这样对性能的影响其实可以忽略不计,没什么大的问题,非要纠结这个性能问题的话,就如我上面说的那样。
public V get(Object key)
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry&K, V& e = table[indexFor(hash, table.length)]; e != e = e.next)
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
上面这段代码是jdk中HashMap的源码,你看源码的Object k定义就在循环体内部的!
放在里面,虽然会在栈内每次都分配一块内存,但是由于栈内存的分配非常之快,仅次于寄存器,所以,可以忽略不计。
在csdn看到的:
引用1.尽量使用final修饰符。
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。
2.尽量重用对象。
特别是String对象的使用中,出现字符串连接情况时应使用StringBuffer代替,由于系统不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理。因此生成过多的对象将会给程序的性能带来很大的影响。
3.尽量使用局部变量。
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量,实例变量等,都在堆(Heap)中创建,速度较慢。
其实你这个例子,对性能没什么关键影响,根本不用纠结
这个还是要看字节码滴:
变量定义在循环内
aload 5 [iterator]
invokeinterface java.util.Iterator.next() : java.lang.Object [38] [nargs: 1]
aload 5 [iterator]
invokeinterface java.util.Iterator.hasNext() : boolean [44] [nargs: 1]
变量定义在循环外
aconst_null
astore 7 [object]
invokeinterface java.util.List.iterator() : java.util.Iterator [34] [nargs: 1]
astore 8 [iterator]
aload 8 [iterator]
invokeinterface java.util.Iterator.next() : java.lang.Object [38] [nargs: 1]
astore 7 [object]
aload 8 [iterator]
invokeinterface java.util.Iterator.hasNext() : boolean [44] [nargs: 1]
现在是不是很清楚了?除了那个Object object = 的定义多了2条指令,其他没有区别。
循环内的话,每次循环内部的局部变量在每次进for循环的时候都要重新定义一遍变量,也就是执行申请内存空间,变量压入堆栈的过程。
循环外定义的话,for循环一直用的是同一块内存空间,效率比较高,但是变量的作用域就大了,耗内存
其实内外都可以的,总之就是空间和时间的权衡,看实际情况了,局部变量的数据类型、大小什么的都有关
个人觉得,对于java来说,本来就不是什么高效的语言& 我习惯于定义在里面
循环外,就只是开辟一块内存空间。而循环里面你每次调都要开辟一次内存空间来存放变量。当然内存使用就高了。循环外定义的好处是在循环结束后变量值如果变化了可以取出来。而在循环里面的变量在外面得不到值,也就是作用域。
已解决问题
未解决问题Java for-each循环解惑 - ImportNew
从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类的代码,这段代码将会打印出什么,抛出异常还是编译器错误:
* 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中添加和删除项的方法。
public class CustomCollection&T&{
private ArrayList&T&
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
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 ,为什么?请注意,答案可能是两个都会,都不会或其中之一。
import java.util.ArrayL
import java.util.C
import java.util.I
* Java class to demonstrate inner working of for-each loop in Java
* @author Javin Paul
public class ForEachTest2 {
public static void main(String args[]){
Collection&String& list = new ArrayList&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。你可以从下面的输出中了解到这点,在注释掉第一个代码段后,当你运行第二个代码段时会得到下面的输出。
Exception in thread &main& java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at test.ForEachTest2.main(ForEachTest2.java:34)
以上就是关于Java5 for-each循环的全部内容。我们已经看到了Java程序员在编写遍历Collection类的代码时产生的很多问题,特别是在遍历collection的同时删除元素的时候。请牢记,在从任何Collection(例如Map、Set或List)中删除对象时总要使用Iterator的remove方法,也请谨记for-each循环只是标准Iterator代码标准用法之上的一种语法糖(syntactic sugar)而已。
译者注:语法糖(syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达-Peter J. Landin发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
原文链接:
- 译文链接: [ 转载请保留原文出处、译者和译文链接。]
关于作者:
(新浪微博:)
好奇import new只是一个爬虫网站吧,没人审核文章质量
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2017 ImportNewjava里for循环与它的前后变量关系 -
- ITeye博客
今天在偶然阅读一份某企业的笔试题的时候看到这样一道java选择题:
下述程序代码中有语法错误的行是(& )。
int&& i, la[10]& ,& lb[10];/*a*/
for(int i=0;i&=9;i++)/*b*/
la[i]=0;/*c*/
A.a B.b& C.c& D.d
题目本身很简单,相信大家已经有自己的选择了。
这里我要说的是,我的选择是AB。
首先数组在初始化的时候才能给定长度,无可置疑。
可能有人要问了变量i是否重复定义了?
for(int i=0;i&=9;i++)
以上语句是否有问题呢?
可能会有人说一样的。但是问题就是,不一样!
你也可以试验一下,以上语句没有问题。因为for循环相当于代码段,是独立的一个块。但是它比较特殊,不同于函数的是,对于函数中定义的变量,有他的作用范围;而位于for语句之前定义的变量或属性将会被for语句识别,并可以直接使用;而位于for语句之后的定义则会被for代码块遗忘,相当于for循环运行完成后,会将for循环以及其之前的所有变量和属性释放,程序告一段落。for循环之后的程序块将另起炉灶。这就是为什么位于for之前的重复命名不被允许的原因。
原谅我如此愚钝,才知道这么回事....
浏览: 17879 次
来自: 北京
可以使用在线按钮样式生成器:http://buttoncssg ...java的for循环一共有几种写法? - 知乎11被浏览3246分享邀请回答107 条评论分享收藏感谢收起0添加评论分享收藏感谢收起查看更多回答

我要回帖

更多关于 java中for循环 的文章

 

随机推荐