当前位置: 首页 > news >正文

Java集合的遍历方式(全解析)

一、集合的遍历方式(全解析)

Java 集合框架中,不同类型的集合(ListSetMap)遍历方式略有差异,但核心目标是访问集合中的每个元素。以下按集合类型分类讲解所有遍历方式,包含语法、适用场景和注意事项。

1. Collection 体系(ListSet)的遍历方式

Collection 是单元素集合的根接口(ListSet 都继承它),通用遍历方式如下:

(1)增强 for 循环(foreach

语法

for (元素类型 变量名 : 集合) {// 操作变量
}

适用场景

  • 仅需读取元素,无需修改集合结构(添加/删除元素)。
  • 所有 Collection 实现类(ListSet 均可)。

优点:代码简洁,可读性高。
缺点

  • 无法获取元素索引(List 也不行)。
  • 遍历中不能修改集合结构(添加/删除元素),否则会抛出 ConcurrentModificationException

示例

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;public class ForEachDemo {public static void main(String[] args) {// List遍历List<String> list = new ArrayList<>();list.add("A");list.add("B");System.out.println("List遍历:");for (String s : list) {System.out.println(s);}// Set遍历Set<Integer> set = new HashSet<>();set.add(1);set.add(2);System.out.println("Set遍历:");for (int num : set) {System.out.println(num);}}
}
(2)迭代器(Iterator

语法

Iterator<元素类型> it = 集合.iterator();
while (it.hasNext()) { // 判断是否有下一个元素元素类型 变量 = it.next(); // 获取下一个元素// 操作变量
}

适用场景

  • 需要在遍历中删除元素(唯一安全的方式)。
  • 所有 Collection 实现类(ListSet 均可)。

优点

  • 支持遍历中安全删除元素(通过 it.remove(),而非集合的 remove())。
  • 可控制遍历过程(如提前终止)。

缺点:代码相对繁琐。

示例

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class IteratorDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("A");list.add("B");list.add("C");Iterator<String> it = list.iterator();while (it.hasNext()) {String s = it.next();if (s.equals("B")) {it.remove(); // 安全删除当前元素(不会抛异常)}}System.out.println("删除后集合:" + list); // [A, C]}
}

注意

  • 调用 it.next() 前必须先调用 it.hasNext(),否则可能抛出 NoSuchElementException
  • 遍历中若通过集合的 remove() 方法删除元素(而非 it.remove()),会触发 ConcurrentModificationException
(3)普通 for 循环(仅适用于 List

语法

for (int i = 0; i < 集合.size(); i++) {元素类型 变量 = 集合.get(i); // 通过索引获取元素// 操作变量
}

适用场景

  • List 集合(因 List 有序且有索引,Set 无序无索引,不支持)。
  • 需要获取元素索引,或需要反向遍历(从后往前)。

优点

  • 可直接获取索引,方便定位元素。
  • 支持修改集合结构(如删除元素后调整索引)。

缺点:仅适用于 ListSet 无法使用。

示例

import java.util.ArrayList;
import java.util.List;public class ForLoopDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(10);list.add(20);list.add(30);// 正向遍历System.out.println("正向遍历:");for (int i = 0; i < list.size(); i++) {System.out.println("索引" + i + ":" + list.get(i));}// 反向遍历System.out.println("反向遍历:");for (int i = list.size() - 1; i >= 0; i--) {System.out.println("索引" + i + ":" + list.get(i));}}
}
(4)ListIterator(仅适用于 List,双向遍历)

ListIteratorIterator 的子接口,仅 List 支持,可双向遍历(向前/向后)和添加元素

语法

ListIterator<元素类型> lit = 列表.listIterator();
// 向后遍历
while (lit.hasNext()) {元素类型 变量 = lit.next();
}
// 向前遍历(需先向后遍历到末尾)
while (lit.hasPrevious()) {元素类型 变量 = lit.previous();
}

适用场景

  • List 集合需要双向遍历(如先向后再向前)。
  • 需要在遍历中添加元素(lit.add(元素))。

示例

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;public class ListIteratorDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("A");list.add("B");ListIterator<String> lit = list.listIterator();// 向后遍历并添加元素while (lit.hasNext()) {String s = lit.next();if (s.equals("B")) {lit.add("C"); // 在B之后添加C}}System.out.println("添加后集合:" + list); // [A, B, C]// 向前遍历System.out.println("向前遍历:");while (lit.hasPrevious()) {System.out.println(lit.previous()); // C → B → A}}
}
(5)Java 8+ forEach 方法(结合 Lambda)

Collection 接口在 Java 8 中新增了 forEach(Consumer<? super T> action) 方法,可通过 Lambda 表达式遍历,代码更简洁。

语法

集合.forEach(元素 -> {// 操作元素
});

适用场景

  • 仅需读取元素,无需修改集合结构。
  • 所有 Collection 实现类(ListSet 均可)。
  • 希望代码更简洁,适合函数式编程风格。

优点:代码最简洁,一行搞定。
缺点:遍历中不能修改集合结构(否则抛异常),且无法直接获取索引。

示例

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;public class ForEachLambdaDemo {public static void main(String[] args) {// List遍历List<String> list = new ArrayList<>();list.add("Java");list.add("Python");System.out.println("List遍历:");list.forEach(s -> System.out.println(s));// Set遍历Set<Integer> set = new HashSet<>();set.add(100);set.add(200);System.out.println("Set遍历:");set.forEach(num -> System.out.println(num));}
}
2. Map 体系的遍历方式

Map 存储键值对(key-value),遍历方式需围绕 keyvalue 或键值对(Entry)展开。

(1)遍历 key 集,再获取 value

步骤

  1. keySet() 获取所有 keySet 集合。
  2. 遍历 key 集,通过 get(key) 获取对应 value

适用场景:需要同时使用 keyvalue,但 key 更易遍历。

示例

import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class MapKeySetDemo {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Java", 90);map.put("Python", 85);// 获取key集Set<String> keys = map.keySet();// 遍历key集for (String key : keys) {Integer value = map.get(key);System.out.println(key + " → " + value);}}
}
(2)遍历 value 集(仅需 value 时)

步骤:用 values() 获取所有 valueCollection 集合,直接遍历。

适用场景:仅需要 value,无需 key

示例

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;public class MapValuesDemo {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Java", 90);map.put("Python", 85);// 获取value集Collection<Integer> values = map.values();// 遍历value集for (int score : values) {System.out.println("分数:" + score);}}
}
(3)遍历键值对(Entry 集,推荐)

Map 中的每个键值对由 Map.Entry<K, V> 对象表示,通过 entrySet() 获取所有 EntrySet 集合,直接遍历键值对,效率最高(无需二次查询 value)。

适用场景:需要同时操作 keyvalue(推荐优先使用)。

示例

import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class MapEntrySetDemo {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Java", 90);map.put("Python", 85);// 获取Entry集Set<Map.Entry<String, Integer>> entries = map.entrySet();// 遍历Entry集for (Map.Entry<String, Integer> entry : entries) {String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + " → " + value);}}
}
(4)Java 8+ forEach 方法(结合 Lambda)

Map 接口在 Java 8 中新增 forEach(BiConsumer<? super K, ? super V> action) 方法,直接通过 Lambda 遍历键值对。

语法

map.forEach((key, value) -> {// 操作key和value
});

适用场景:需要简洁代码同时操作 keyvalue

示例

import java.util.HashMap;
import java.util.Map;public class MapForEachLambdaDemo {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Java", 90);map.put("Python", 85);// Lambda遍历键值对map.forEach((key, value) -> {System.out.println(key + " → " + value);});}
}

二、集合的选择:什么时候用哪种集合?

集合的选择需根据业务需求(如是否有序、是否去重、操作效率等)决定,核心参考以下维度:

1. 先确定集合类型:ListSet 还是 Map
  • List:需要有序、可重复的元素(如列表、数组扩展)。
  • Set:需要无序、不可重复的元素(如去重、唯一标识)。
  • Map:需要键值对映射(如字典、缓存、索引表)。
2. List 实现类的选择
实现类底层结构核心特点适用场景
ArrayList动态数组查询快(O(1)),增删慢(中间位置 O(n)频繁查询、少量增删(如用户列表、商品列表)
LinkedList双向链表增删快(首尾 O(1)),查询慢(O(n)频繁增删(如队列、栈、链表结构)
3. Set 实现类的选择
实现类底层结构核心特点适用场景
HashSet哈希表无序,去重,增删查效率高(O(1)仅需去重,无需排序(如用户ID集合)
TreeSet红黑树有序(自然排序/自定义排序),去重去重且需要排序(如排行榜、按规则排序的唯一元素)
4. Map 实现类的选择
实现类底层结构核心特点适用场景
HashMap哈希表key无序,增删查效率高(O(1)),非线程安全一般键值对存储(如缓存、配置映射)
TreeMap红黑树key有序(自然排序/自定义排序)需要按key排序的键值对(如按日期排序的日志)
ConcurrentHashMap哈希表(分段锁)线程安全,高效并发,key无序多线程环境下的键值对存储

三、集合使用的最佳实践

  1. 优先选择具体实现类:声明集合时用接口(如 List<String> list = new ArrayList<>()),便于后续替换实现类。
  2. 初始化时指定容量:如 new ArrayList<>(100),避免频繁扩容(哈希表默认容量16,负载因子0.75)。
  3. 遍历方式选择
    • 仅读取:用 forEach(Lambda)最简洁。
    • 需要删除元素:用 IteratorList 也可用普通for循环,但需注意索引调整)。
    • 需要索引:List 用普通for循环。
    • Map 优先用 entrySet() 遍历键值对(效率最高)。
  4. 避免集合嵌套过深:如 Map<String, List<Map<String, Object>>> 会降低可读性,建议用实体类封装。
  5. 线程安全考量:多线程场景下,ArrayList/HashMap 需替换为 CopyOnWriteArrayList/ConcurrentHashMap(而非 Collections.synchronizedList(),效率更高)。

总结

  • 遍历方式:根据集合类型(List/Set/Map)和需求(是否修改、是否需要索引)选择,Iterator 适合删除元素,forEach(Lambda)适合简洁读取,entrySet()Map 最高效的遍历方式。
  • 集合选择:根据“有序性”“重复性”“操作效率”决策——List 有序可重复,Set 无序去重,Map 键值对映射;具体实现类按查询/增删效率、排序需求选择。

掌握这些规则,能写出高效、易维护的集合操作代码。

如需巩固本文内容,可点击以下链接完成相关练习:点击此处进入练习题。

http://www.dtcms.com/a/320229.html

相关文章:

  • 力扣经典算法篇-46-阶乘后的零(正向步长遍历,逆向步长遍历)
  • BGP笔记整理
  • Maven高级:继承与聚合实战指南
  • RS485转Profibus网关在QDNA钠离子分析仪与300PLC通信中的应用解析
  • 【OCCT+ImGUI系列】013-碰撞检测-包围盒Bnd_Box
  • 【入门级-C++程序设计:9、函数与递归-函数定义与调用、形参与实参】
  • RESTful 服务概述:从理念到实践的全面解析
  • Coze开放平台综合文档指南
  • 达梦包含OR条件的SQL特定优化----INJECT-HINT优化方法
  • 最新完整内、外期货量化交易系统C#源码可售
  • 【C#补全计划:类和对象(九)】接口
  • redis--黑马点评--用户签到模块详解
  • dubbo源码之编解码逻辑
  • 一场 Dark Theme A/B 测试的复盘与提效实践
  • 聚集索引VS非聚集索引:核心差异详解
  • rebase 和pull的通俗区别是什么
  • 一个基于固定 IP地址查询天气的 C 语言程序,通过调用第三方天气 API:
  • React 多语言(i18n)方案全面指南
  • 计算机英语详细总结
  • 本地化密码恢复工具的技术实现与应用边界
  • RabbitMQ面试精讲 Day 13:HAProxy与负载均衡配置
  • Git `cherry-pick` 工具汇总
  • Docker 加载镜像时出现 “no space left on device” 错误的解决方法
  • Java Lambda表达式:简洁高效的函数式编程
  • 关于光猫研究
  • 【代码随想录day 14】 力扣 101. 对称二叉树
  • 技法笔记3 | 验证交互式shell连接
  • LocalSqueeze(图片压缩工具) v1.0.4 压缩
  • 美图复现|Science:添加显著性的GO富集分析美图
  • Nuxt 4.0 完全指南:Nitro 引擎升级与 Composable API 深度解析