学科分类
目录
Java基础

foreach遍历集合

虽然Iterator可以用来遍历集合中的元素,但写法上比较繁琐,为了简化书写,从JDK 5开始,提供了foreach循环。foreach循环是一种更加简洁的for循环,也称增强for循环。foreach循环用于遍历数组或集合中的元素,其具体语法格式如下:

for(容器中元素类型 临时变量 :容器变量) {
  // 执行语句
}

从上面的格式可以看出,与for循环相比,foreach循环不需要获得容器的长度,也不需要根据索引访问容器中的元素,但它会自动遍历容器中的每个元素。接下来通过一个案例对foreach循环进行详细讲解,如文件1所示。

文件1 Example04.Java

 1    import java.util.ArrayList;
 2    public class Example04 {
 3        public static void main(String[] args) {
 4            ArrayList list = new ArrayList();     
 5            list.add("data_1");                     
 6            list.add("data_2");
 7            list.add("data_3");        
 8             // 使用foreach循环遍历集合
 9            for (Object obj : list) {    
 10                 System.out.println(obj);    // 取出并打印集合中的元素
 11            }
 12        }
 13    }

运行结果如图1所示。

图1 运行结果

通过文件1可以看出,foreach循环遍历集合的语法非常简洁,没有循环条件,也没有迭代语句,所有这些工作都交给JVM去执行了。foreach循环的次数是由容器中元素的个数决定的,每次循环时,foreach中都通过变量将当前循环的元素记住,从而将集合中的元素分别打印出来。

脚下留心:

1.foreach循环虽然书写起来很简洁,但在使用时也存在一定的局限性。当使用foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改,接下来以一个String类型的数组为例来进行演示,如文件2所示。

文件2 Example05.java

 1    public class Example05 {
 2        static String[] strs = { "aaa", "bbb", "ccc" };
 3        public static void main(String[] args) {
 4            // 1、foreach循环遍历数组
 5            for (String str : strs) {
 6                str = "ddd";
 7            }
 8            System.out.println("foreach循环修改后的数组:" + strs[0] + ","
 9                                     + strs[1] + "," + strs[2]);
 10            // 2、for循环遍历数组
 11            for (int i = 0; i < strs.length; i++) {
 12                strs[i] = "ddd";
 13            }
 14            System.out.println("普通for循环修改后的数组:" + strs[0] + ","
 15                                   + strs[1] + "," + strs[2]);
 16        }
 17    }

运行结果如图2所示。

图2 运行结果

在文件2中,分别使用foreach循环和普通for循环去修改数组中的元素。从运行结果可以看出foreach循环并不能修改数组中元素的值。其原因是第6行代码中的str = "ddd"只是将临时变量str指向了一个新的字符串,这和数组中的元素没有一点关系。而在普通for循环中,是可以通过索引的方式来引用数组中的元素并将其值进行修改的。

2.在使用Iterator迭代器对集合中的元素进行迭代时,如果调用了集合对象的remove()方法去删除元素,会出现异常。接下来通过一个案例来演示这种异常,如文件3所示。

文件3 Example06.java

 1    import java.util.ArrayList;
 2    import java.util.Iterator;
 3    public class Example06 {
 4        public static void main(String[] args) {
 5        ArrayList list = new ArrayList();     
 6            list.add("Jack");
 7            list.add("Annie");
 8            list.add("Rose");
 9            list.add("Tom");
 10            Iterator it = list.iterator();   // 获得Iterator对象
 11            while (it.hasNext()) {            // 判断该集合是否有下一个元素
 12                Object obj = it.next();      // 获取该集合中的元素
 13                if ("Annie".equals(obj)) {  // 判断该集合中的元素是否为Annie
 14                    list.remove(obj);        // 删除该集合中的元素
 15                }
 16            }
 17             System.out.println(list);
 18        }
 19    }

运行结果如图3所示。

图3 运行结果

文件3在运行时出现了并发修改异常ConcurrentModificationException。这个异常是迭代器对象抛出的,出现异常的原因是集合中删除了元素会导致迭代器预期的迭代次数发生改变,导致迭代器的结果不准确。

为了解决上述问题,可以采用两种方式,具体如下:

第一种方式:从业务逻辑上讲只想将元素Annie删除,至于后面还有多少元素我们并不关心,所以只需找到该元素后跳出循环不再迭代即可,也就是在第14行代码下面增加一个break语句,代码如下:

if ("Annie".equals(obj)) {
    list.remove(obj);
    break;
}

在使用break语句跳出循环以后,由于没有继续使用迭代器对集合中的元素进行迭代,因此,集合中删除元素对程序没有任何影响,不会出现异常。

第二种方式:如果需要在集合的迭代期间对集合中的元素进行删除,可以使用迭代器本身的删除方法,将文件3中第14行代码替换成it.remove()即可解决这个问题,代码如下:

if ("Annie".equals(obj)) { 
    it.remove(); 
}

替换代码后再次运行程序,运行结果如图4所示。

图4 运行结果

从图4可以看出,元素Annie确实被删除了,并且没有出现异常。因此可以得出结论,调用迭代器对象的remove()方法删除元素所导致的迭代次数变化,对于迭代器对象本身来讲是可预知的。

点击此处
隐藏目录