我是靠谱客的博主 强健果汁,最近开发中收集的这篇文章主要介绍foreach循环,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.foreach循环

本篇文章参考纯洁的微笑文章 :http://www.justdojava.com/2019/12/14/java-foreach/

foreach简直就是功能强大,不管是什么数组,集合都可以用foreach搞定,比如小马哥的上一篇博客中:https://blog.csdn.net/weixin_44109717/article/details/113651457

写到了for循环的日子,我们可以这样用,

enum OptionFirst {Tom, Jerry, Jack, Mary}
enum OptionSecond {Tom, Jerry, Jack, Mary, Mali, Tomsun, Lijie, Oolyyou}
Collection<OptionFirst> optionFirstCollection = Arrays.asList(OptionFirst.values());
Collection<OptionSecond> optionSecondCollection = Arrays.asList(OptionSecond.values());
for (OptionFirst optiionFirst: optionFirstCollection) {
for (OptionSecond optiionSecond: optionSecondCollection){
System.out.printf(optiionFirst+"----"+optiionSecond);
System.out.printf("n");
}

就能准确的输出结果,但是foreach真的什么场合都可以使用吗?

下面为大家具体以下3种场合不能使用foreach循环

1.1、解构过滤的时候不能使用

如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。不过在Java8中增加的Collection的removeIf方法常常可以避免显式的遍历。

例如下面这段代码:

List<String> list = new ArrayList<String>();
list.add("1"); list.add("2");
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
System.out.println("执行if语句成功");
}
}

直接运行这段代码是没什么问题的,数组list能成功删除元素1,也能打印对应语句。

但是,我们进行如下任意一种操作:

  • 若把list.remove(item)换成list.add(“3”);操作如何?
  • 若在第6行添加list.add(“3”);那么代码会出错吗?
  • 若把if语句中的“1”换成“2”,结果你感到意外吗?

如果都能正确执行当然就不需要问了,所以3个都会报ConcurrentModificationException的异常;

执行结果异常

而出现这些情况的原因稍稍解释下就是:

首先,这涉及多线程操作,Iterator是不支持多线程操作的,List类会在内部维护一个modCount的变量,用来记录修改次数。

举例:ArrayList源码

protected transient int modCount = 0;

每生成一个Iterator,Iterator就会记录该modCount,每次调用next()方法就会将该记录与外部类List的modCount进行对比,发现不相等就会抛出多线程编辑异常。

为什么这么做呢?我的理解是你创建了一个迭代器,该迭代器和要遍历的集合的内容是紧耦合的,意思就是这个迭代器对应的集合内容就是当前的内容,我肯定不会希望在我冒泡排序的时候,还有线程在向我的集合里插入数据对吧?所以Java用了这种简单的处理机制来禁止遍历时修改集合。

至于为什么删除“1”就可以呢,原因在于foreach和迭代器的hasNext()方法,foreach这个语法,实际上就是

while(itr.hasNext()){
itr.next() }

所以每次循环都会先执行hasNext(),那么看看ArrayList的hasNext()是怎么写的:

public boolean hasNext() {
return cursor != size; }

cursor是用于标记迭代器位置的变量,该变量由0开始,每次调用next执行+1操作,于是:

所以代码在执行删除“1”后,size=1,cursor=1,此时hasNext()返回false,结束循环,因此你的迭代器并没有调用next查找第二个元素,也就无从检测modCount了,因此也不会出现多线程修改异常;但当你删除“2”时,迭代器调用了两次next,此时size=1,cursor=2,hasNext()返回true,于是迭代器傻乎乎的就又去调用了一次next(),因此也引发了modCount不相等,抛出多线程修改的异常。

当你的集合有三个元素的时候,你就会神奇的发现,删除“1”是会抛出异常的,但删除“2”就没有问题了,究其原因,和上面的程序执行顺序是一致的。

因此,在《阿里巴巴Java开发手册中有这样一条规定》:

img

1.2、转换

如果需要遍历列表或数组,并取代它的部分或者全部元素值,就需要使用列表迭代器或者数组索引,以便替换元素的值。

因为for-each是一循到底的,中间不做停留和位置信息的显示;所以要替换元素就不能使用它了。

1.3、平行迭代

如果需要并行的遍历多个集合,就需要显式的控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以同步前进(就像上面讲述Iterator迭代器的时候提到的组合减少的情况,只想出现下标一一对应的元素组合)。

最后

以上就是强健果汁为你收集整理的foreach循环的全部内容,希望文章能够帮你解决foreach循环所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部