007Java集合011遍历集合元素并修改
注意:本文基于JDK1.8进行记录。
1 遍历Collection
对List和Set的遍历,有四种方式,下面以ArrayList为例进行说明。
1.1 普通for循环
使用普通for循环的遍历方式效率最高,尽量将循环无关的代码放置在集合外执行。
代码如下:
1 for (int i = 0; i < list.size(); i++) { 2 System.out.println(i); 3 }
如果要在普通for循环里对集合元素进行删除操作,可能会出现问题:
1 public static void main(String[] args) { 2 List<Integer> list = new ArrayList<Integer>(); 3 list.add(1); 4 list.add(2); 5 list.add(2); 6 list.add(4); 7 list.add(5); 8 for (int i = 0; i < list.size(); i++) { 9 if (list.get(i) == 2) { 10 list.remove(i); 11 } 12 } 13 System.out.println(list); 14 }
运行结果如下:
1 [1, 2, 4, 5]
结果说明:
集合中有两个值为2的元素,但是在代码执行之后,值为2的元素并没有完全移除。
在第一次删除后,集合发生了改变,删除位置之后的所有元素都向前挪动了一个位置,删除位置上的元素由下一位置上的元素替代。
在下次遍历时,从删除位置后开始判断,跳过了删除位置上的元素,从而导致最后打印的结果和预期的不一致。
改进的办法是在删除之后设置索引减1,重新判断删除位置上的元素。
1.2 增强for循环
进一步精简了遍历的代码,底层使用迭代器。
代码如下:
1 for (Integer i : list) { 2 System.out.println(i); 3 }
如果在增强for循环里删除或者添加集合元素,那么一定会报异常:
1 public static void main(String[] args) { 2 List<Integer> list = new ArrayList<Integer>(); 3 list.add(1); 4 list.add(2); 5 list.add(2); 6 list.add(4); 7 list.add(5); 8 for (Integer i : list) { 9 if (i == 2) { 10 list.remove(i); 11 } 12 } 13 System.out.println(list); 14 }
运行结果如下:
1 java.util.ConcurrentModificationException
结果说明:
抛出ConcurrentModificationException异常是由快速失败(fail-fast)机制引起的,该机制是为了避免在遍历集合时,对集合的结构进行修改。
快速失败机制使用modCount记录集合的修改次数,在删除时除了删除对应元素外,还会更新modCount。
增强for循环本质上是使用迭代器进行遍历,迭代器在初始化时会使用expectedModCount记录当时的modCount,遍历时会检查expectedModCount是否和modCount相同,如果不同就会抛出ConcurrentModificationException异常。
1.3 使用迭代器
代码如下:
1 Iterator<Integer> iterator = list.iterator(); 2 while (iterator.hasNext()) { 3 System.out.println(iterator.next()); 4 }
如果在迭代器中使用集合提供的删除或添加方法,同样会报错:
1 public static void main(String[] args) { 2 List<Integer> list = new ArrayList<Integer>(); 3 list.add(1); 4 list.add(2); 5 list.add(2); 6 list.add(4); 7 list.add(5); 8 Iterator<Integer> iterator = list.iterator(); 9 while (iterator.hasNext()) { 10 if (iterator.next() == 2) { 11 list.add(6); 12 } 13 } 14 System.out.println(list); 15 }
运行结果如下:
1 java.util.ConcurrentModificationException
结果说明:
这里抛出异常的原因和增强for循环一样,同样是因为快速失败机制。
解决办法是在迭代器中删除或添加元素时,使用迭代器提供的删除或添加方法,不要使用集合提供的删除或添加方法。
需要注意的是,普通迭代器中只提供了删除方法,在集合迭代器中还提供了添加和修改方法。
1.4 使用集合迭代器
代码如下:
1 ListIterator<Integer> iterator = list.listIterator(); 2 while (iterator.hasNext()) { 3 System.out.println(iterator.next()); 4 }
在迭代器中使用迭代器提供的删除或添加方法:
1 public static void main(String[] args) { 2 List<Integer> list = new ArrayList<Integer>(); 3 list.add(1); 4 list.add(2); 5 list.add(2); 6 list.add(4); 7 list.add(5); 8 ListIterator<Integer> iterator = list.listIterator(); 9 while (iterator.hasNext()) { 10 if (iterator.next() == 2) { 11 iterator.remove(); 12 } 13 } 14 System.out.println(list); 15 }
运行结果如下:
1 [1, 4, 5]
结果说明:
迭代器提供的方法同时维护了modCount和expectedModCount,所以不会产生快速失败。
1.5 使用forEach方法
forEach方法是JDK1.8新增的方法,需要配合Lambda表达式使用,代码如下:
1 list.forEach(i -> System.out.println(i));
使用forEach方法遍历:
1 public static void main(String[] args) { 2 List<Integer> list = new ArrayList<Integer>(); 3 list.add(1); 4 list.add(2); 5 list.add(2); 6 list.add(4); 7 list.add(5); 8 list.forEach(i -> { 9 if (i == 2) { 10 list.remove(i); 11 } 12 }); 13 System.out.println(list); 14 }
运行结果如下:
1 java.util.ConcurrentModificationException
结果说明:
这里抛出异常的原因也是因为快速失败机制。
2 遍历Map
对Map的遍历,有四种方式,下面以HashMap为例进行说明。
2.1 通过keySet()方法遍历key和value
通过keySet()方法获取到map的所有key值,遍历key值的集合,获取对应的value值。代码如下:
1 for (Integer i : map.keySet()) { 2 System.out.println(i + " >>> " + map.get(i)); 3 }
运行结果如下:
1 0 >>> 000 2 1 >>> 111 3 2 >>> 222 4 3 >>> 333 5 4 >>> 444
在遍历的时候是可以修改的,但是不能添加和删除,否则会抛出ConcurrentModificationException异常,代码如下:
1 for (Integer i : map.keySet()) { 2 System.out.println(i + " >>> " + map.get(i)); 3 if (map.get(i) == "222") { 4 map.put(i, "999"); 5 } 6 }
运行结果如下:
1 0 >>> 000 2 1 >>> 111 3 2 >>> 999 4 3 >>> 333 5 4 >>> 444
2.2 通过entrySet()方法遍历key和value
这种方式同样支持修改,但不支持添加和删除,这种方式的效率最高,代码如下:
1 for (Map.Entry<Integer, String> entry : map.entrySet()) { 2 System.out.println(entry.getKey() + " >>> " + entry.getValue()); 3 }
2.3 通过entrySet()方法获取迭代器遍历key和value
这种方式同样支持修改,但不支持添加和删除,代码如下:
1 Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator(); 2 while (iterator.hasNext()) { 3 Map.Entry<Integer, String> entry = iterator.next(); 4 System.out.println(entry.getKey() + " >>> " + entry.getValue()); 5 }
2.4 通过values()方法遍历所有的value
这种方式只能遍历value,不能遍历key,代码如下:
1 for (String value : map.values()) { 2 System.out.println(value); 3 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)