Java各种集合,遍历方式详细总结

Java集合遍历方法总结
本文详细介绍了Java中各种集合类型的遍历方法,包括List、Set、Map等,并对比了不同集合类型的遍历效率。

首先说些注意事项:

Iterator 要注意 一个迭代器只能用一次:

//分别取键值

it.forEachRemaining(o1->System.out.println(o1.getKey()));

it.forEachRemaining((o1)->System.out.println(o1.getValue()));

第二条语句打印值 就一个都不会出现,因为 迭代器就类似指针,第一条语句指到了map的结尾 那么  第二条语句就没法执行了 当然这个不会报错 因为只是后边没东西了 所以自己就结束了

 

 

foreach  在内不能直接修改元素  改不出去

 

 

 

 

List:

 

 

ArrayList:

package day0818;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Demo1 {
	public static void main(String[] args) {
		//ArrayList集合遍历
		List<Integer> list=new ArrayList<>();
		//1.forEach
		list.forEach(System.out::println);
		//2.for循环
		// list.get()
		for(int index=0;index<list.size();index++) {
			System.out.println(list.get(index));
		}
		//2.2 list.remove  当然这个遍历完 集合也就空了
		while(list.size()>0) {
			System.out.println(list.remove(0));
		}
		//3.foreach
		for(Integer a:list) {
			System.out.println(a);
		}
		//4.迭代器
		Iterator<Integer> it=list.iterator();
		//4.1迭代器的forEach方法
		it.forEachRemaining(System.out::println);
		//4.2while
		//it.next()
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		// 5.转成数组 再遍历数组
		Integer[] a1 = new Integer[list.size()];
		list.toArray(a1);
		for (Integer temp : a1) {
			System.out.println(temp);
		}
		//第二种初始化方式
		Integer[] a2=(Integer[])list.toArray(new Integer[0]);
		for (Integer temp : a2) {
			System.out.println(temp);
		}
		//6. ListIterator  在使用List、ArrayList、LinkedList和Vector的时候可以使用。
		ListIterator<Integer> listIterator=list.listIterator();
		//迭代器方法通用
		listIterator.forEachRemaining(System.out::println);
		//正着来
		while(listIterator.hasNext()) {
			System.out.println(listIterator.next());
		}
		//倒着来
		while(listIterator.hasPrevious()) {
			System.out.println(it.next());
		}
		//也可以 通过迭代器拿到下标后再取得元素
		while(listIterator.hasNext()) {
			list.get(listIterator.nextIndex());
		}
		//7.Stream  来自Java 1.8 的 集合专属工具类
		//输出结果不一定按顺序来 并行处理
		list.stream().forEach(System.out::println);
		//按顺序来的
		list.stream().forEachOrdered(System.out::println);
		
		
	}

}

 

 

LinkedList:

初学者一定很奇怪,这俩一定有什么区别吧,毕竟底层实现不同,然而事实是没什么区别,当然我这里说的是方法没什么区别,都是那几个方法,但是效率不一样,所以面试一般会问这个,链表的话最好不要用于循环而是用的foreach和迭代器,的foreach其实原理也是迭代器,用于的话,效率真的挺低的,我为了省事,直接复制了⬇️。

 

package day0818;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

public class Demo2 {
	public static void main(String[] args) {
		List<Integer> list = new LinkedList<>();
		// 1.forEach
		list.forEach(System.out::println);
		// 2.for循环
		// list.get()
		for (int index = 0; index < list.size(); index++) {
			System.out.println(list.get(index));
		}
		// 2.2 list.remove 当然这个遍历完 集合也就空了
		while (list.size() > 0) {
			System.out.println(list.remove(0));
		}
		// 3.foreach
		for (Integer a : list) {
			System.out.println(a);
		}
		// 4.迭代器
		Iterator<Integer> it = list.iterator();
		// 4.1迭代器的forEach方法
		it.forEachRemaining(System.out::println);
		// 4.2while
		// it.next()
		while (it.hasNext()) {
			System.out.println(it.next());
		}
		// 5.转成数组 再遍历数组
		Integer[] a1 = new Integer[list.size()];
		list.toArray(a1);
		for (Integer temp : a1) {
			System.out.println(temp);
		}
		//第二种初始化方式
		Integer[] a2=(Integer[])list.toArray(new Integer[0]);
		for (Integer temp : a2) {
			System.out.println(temp);
		}6. ListIterator 在使用List、ArrayList、LinkedList和Vector的时候可以使用。
		ListIterator<Integer> listIterator = list.listIterator();
		// 迭代器方法通用
		listIterator.forEachRemaining(System.out::println);
		// 正着来
		while (listIterator.hasNext()) {
			System.out.println(listIterator.next());
		}
		// 倒着来
		while (listIterator.hasPrevious()) {
			System.out.println(it.next());
		}
		// 也可以 通过迭代器拿到下标后再取得元素
		while (listIterator.hasNext()) {
			list.get(listIterator.nextIndex());
		}
		// 7.Stream 来自Java 1.8 的 集合专属工具类
		// 输出结果不一定按顺序来 并行处理
		list.stream().forEach(System.out::println);
		// 按顺序来的
		list.stream().forEachOrdered(System.out::println);
	}

}

 

Set

 

 

TreeSet:

因为也是由Collection 来的,所以用法上其实和 List 区别不大,但是 和List有着根本的区别,一言以蔽之,就是 有序,无下标,唯一;而 List 则无序 可重复,有下标。

所以很显然了,靠下标遍历的for循环不能用了

 

package day0818;

import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import java.util.TreeSet;

public class Demo3 {
	public static void main(String[] args) {
		Set<Integer> set = new TreeSet<>();
		set.add(1);
		 //1.forEach
		set.forEach(System.out::println);
		// 2.for循环
		// 2.2 set.remove 需要传入元素,且这个返回值是boolean类型,所以也是没法用的
//		 while(set.size()>0) {
//		 System.out.println(set.remove(0));
//		 }
		// 3.foreach  之前说了它相当于迭代器,所以也能用
		for (Integer a : set) {
			System.out.println(a);
		}
		// 4.迭代器
		Iterator<Integer> it = set.iterator();
		// 4.1迭代器的forEach方法
		it.forEachRemaining(System.out::println);
		// 4.2while
		// it.next()
		while (it.hasNext()) {
			System.out.println(it.next());
		}
		// 5.转成数组 再遍历数组
		Integer[] a1 = new Integer[set.size()];
		set.toArray(a1);
		for (Integer temp : a1) {
			System.out.println(temp);
		}
		// 第二种初始化方式
		Integer[] a2 = (Integer[]) set.toArray(new Integer[0]);
		for (Integer temp : a2) {
			System.out.println(temp);
		}
		// 6. ListIterator 在使用list、Arrayset、Linkedset和Vector的时候可以使用。

		// 7.Stream 来自Java 1.8 的 集合专属工具类
		// 输出结果不一定按顺序来 并行处理
		set.stream().forEach(System.out::println);
		// 按顺序来的
		set.stream().forEachOrdered(System.out::println);

	}

}

 

Map

 

HashMap:

 

package day0818;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Demo4 {
	public static void main(String[] args) {
		Map<String, Integer> map=new HashMap<>();
		map.put("aa", 123);
		map.put("bbb", 321);
		//1.forEach
		map.forEach((k,v)->System.out.println(k+","+v));
		//2.for循环 在这里也是不行的
		//3.foreach  要通过 entryset 变为 键值set
		for(Map.Entry<String,Integer> m:map.entrySet()) {
			System.out.println(m.getKey()+","+m.getValue());
		}
		//4.迭代器  也需要变成EntrySet   
		Iterator<Entry<String, Integer>> it=map.entrySet().iterator();
		//分别取键值
		it.forEachRemaining(o1->System.out.println(o1.getKey()));
		it.forEachRemaining((o1)->System.out.println(o1.getValue()));
		//或者
		Set<Entry<String, Integer>> entry=map.entrySet();
		entry.iterator().forEachRemaining((o1)->System.out.println(o1.getKey()));
		entry.iterator().forEachRemaining((o1)->System.out.println(o1.getValue()));
		//5.entry 的forEach
		entry.forEach((o1)->System.out.println(o1.getKey()+","+o1.getValue()));
		//6.把键值分别转成 set  和list  集合 再遍历
		map.keySet().iterator().forEachRemaining(System.out::println);
		map.values().iterator().forEachRemaining(System.out::println);
		//7.流
		map.entrySet().stream().forEach((o1)->System.out.println(o1.getKey()+","+o1.getValue()));
		map.entrySet().stream().forEachOrdered((o1)->System.out.println(o1.getKey()+","+o1.getValue()));
		
	}

}

Queue 

 

ArrayQueue:

本以为数组队列可以有下标 结果发现也是取不到下标的

package day0818;

import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Queue;

public class Demo5 {
	public static void main(String[] args) {
		Queue<Integer> q=new ArrayDeque<>();
		q.add(1);
		q.offer(2);
		//1.forEach
				q.forEach(System.out::println);
				//2.for循环
				//2.2 q.remove  当然这个遍历完 集合也就空了
				while(q.size()>0) {
//					System.out.println(q.remove());
					//或者
					System.out.println(q.peek());
				}
				//3.foreach
				for(Integer a:q) {
					System.out.println(a);
				}
				//4.迭代器
				Iterator<Integer> it=q.iterator();
				//4.1迭代器的forEach方法
				it.forEachRemaining(System.out::println);
				//4.2while
				//it.next()
				while(it.hasNext()) {
					System.out.println(it.next());
				}
				// 5.转成数组 再遍历数组
				Integer[] a1 = new Integer[q.size()];
				q.toArray(a1);
				for (Integer temp : a1) {
					System.out.println(temp);
				}
				//第二种初始化方式
				Integer[] a2=(Integer[])q.toArray(new Integer[0]);
				for (Integer temp : a2) {
					System.out.println(temp);
				}
				//6. ListIterator  在使用q、Arrayq、Linkedq和Vector的时候可以使用。
				//7.Stream  来自Java 1.8 的 集合专属工具类
				//输出结果不一定按顺序来 并行处理
				q.stream().forEach(System.out::println);
				//按顺序来的
				q.stream().forEachOrdered(System.out::println);
	}

}

链表队列:

package day0818;

import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Queue;

public class Demo5 {
	public static void main(String[] args) {
		Queue<Integer> q = new LinkedList<>();
		q.add(1);
		q.offer(2);
		// 1.forEach
		q.forEach(System.out::println);
		// 2.for循环
		// 2.2 q.remove 当然这个遍历完 集合也就空了
		while (q.size() > 0) {
			// System.out.println(q.remove());
			// 或者
			System.out.println(q.peek());
		}
		// 3.foreach
		for (Integer a : q) {
			System.out.println(a);
		}
		// 4.迭代器
		Iterator<Integer> it = q.iterator();
		// 4.1迭代器的forEach方法
		it.forEachRemaining(System.out::println);
		// 4.2while
		// it.next()
		while (it.hasNext()) {
			System.out.println(it.next());
		}
		// 5.转成数组 再遍历数组
		Integer[] a1 = new Integer[q.size()];
		q.toArray(a1);
		for (Integer temp : a1) {
			System.out.println(temp);
		}
		// 第二种初始化方式
		Integer[] a2 = (Integer[]) q.toArray(new Integer[0]);
		for (Integer temp : a2) {
			System.out.println(temp);
		}
		// 6. ListIterator 在使用q、Arrayq、Linkedq和Vector的时候可以使用。
		// 7.Stream 来自Java 1.8 的 集合专属工具类
		// 输出结果不一定按顺序来 并行处理
		q.stream().forEach(System.out::println);
		// 按顺序来的
		q.stream().forEachOrdered(System.out::println);
	}

}

感觉队列都一样,别的就不介绍了。剩下的只是存储是 比如PriorityQueue 优先队列 可以自定义顺序等等,具体介绍在之前的 集合 文章里有

 

Deque 也是一样的  所以这篇文章就到这里吧。

感谢阅读,有错误的地方,望指出。谢谢

<think>我们正在讨论Java集合遍历方式对比。根据引用内容,常见的遍历方式有:使用keySet遍历Map、使用entrySet遍历Map、使用values遍历Map的值,以及使用foreach循环和Iterator迭代器遍历。此外,增强for循环(foreach)底层也是基于迭代器实现的。 需要对比的方面包括: 1. 遍历方式的写法(简洁性) 2. 性能(速度) 3. 功能(是否可以在遍历时删除元素等) 4. 适用场景 根据引用内容: - 引用[1]提到Map的三种遍历方式:keySet、entrySet、values,并指出entrySet方式性能较好。 - 引用[2]指出foreach循环简洁,但不能在遍历时删除元素,且性能比直接使用Iterator稍慢(因为涉及类型转换)。 - 引用[3]展示了keySet遍历的代码示例。 - 引用[4]解释了增强for循环的原理(基于Iterable接口,使用迭代器)。 因此,我们可以从以下角度进行对比: 一、Map集合遍历方式: 1. keySet遍历:先获取所有键的集合,再通过键获取值。 2. entrySet遍历:直接获取键值对的集合,然后遍历每个键值对。 3. values遍历:仅遍历值,不涉及键。 二、通用集合(如List、Set)的遍历方式: 1. 普通for循环(使用索引) 2. 增强for循环(foreach) 3. 迭代器(Iterator) 三、性能对比: 根据引用[1],在Map遍历中,entrySet方式性能优于keySet方式,因为keySet方式需要先获取键,再通过键获取值,相当于两次查找;而entrySet方式一次获取键值对,效率更高。 对于List集合,引用[2]提到foreach循环基于Iterator实现,但由于类型转换,性能略低于直接使用Iterator。而普通for循环在随机访问列表(如ArrayList)中效率高,但在链表(LinkedList)中效率低,因为链表随机访问需要遍历。 四、功能对比: - 使用Iterator可以在遍历时安全地删除元素(通过remove方法)。 - 增强for循环不能直接删除元素,否则会抛出ConcurrentModificationException。 - 普通for循环可以通过索引删除,但需要调整索引,容易出错。 下面我们进行详细对比: 1. Map遍历方式: - keySet遍历:适用于只需要键或需要键和值但不太关心性能的场景。 - entrySet遍历:推荐方式,性能最好,尤其是需要键和值时。 - values遍历:仅需要值的时候使用。 2. 通用集合遍历方式: - 普通for循环:适合支持随机访问的集合(如ArrayList),通过索引直接访问元素。不适用于LinkedList(效率低)。 - 增强for循环:语法简洁,适用于任何实现了Iterable接口的集合。不能修改集合(删除元素),否则会抛出异常。 - 迭代器:可以在遍历过程中安全删除元素,适用于所有集合。 性能对比总结(引用[1][2]): - Map遍历:entrySet > keySet(entrySet比keySet快,因为减少查找次数) - List遍历(ArrayList): 普通for循环 ≈ 迭代器 > 增强for循环(但差异很小,除非数据量极大) LinkedList: 迭代器 >> 普通for循环(因为普通for循环在LinkedList中通过索引访问是O(n)的,而迭代器是O(1)) 因此,我们给出以下建议: - 遍历Map:优先使用entrySet的增强for循环或迭代器。 - 遍历ArrayList:三种方式均可,数据量大时普通for循环和迭代器性能相近,但普通for循环更直观。 - 遍历LinkedList:必须使用迭代器或增强for循环(底层也是迭代器),避免使用普通for循环。 代码示例: Map遍历(entrySet): ```java Map<String, Integer> map = new HashMap<>(); for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); // 处理键值对 } ``` List遍历(增强for循环): ```java List<String> list = new ArrayList<>(); for (String s : list) { // 处理元素 } ``` 使用迭代器(可删除元素): ```java Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.next(); if (s.equals("remove")) { iterator.remove(); // 安全删除 } } ``` 普通for循环(ArrayList): ```java for (int i = 0; i < list.size(); i++) { String s = list.get(i); // 处理元素 } ``` 注意:在遍历过程中修改集合结构(添加、删除)时,只有使用迭代器的remove方法是安全的。其他方式可能会抛出ConcurrentModificationException。 总结表格: | 遍历方式 | 适用场景 | 性能(推荐场景) | 是否可修改集合(删除) | |--------------------|--------------------------------------|--------------------------------------|------------------------| | Map.keySet | 需要键或通过键取值 | 较慢(不推荐) | 不可直接删除 | | Map.entrySet | 需要键和值(推荐) | 快(推荐) | 可通过迭代器删除 | | Map.values | 只需要值 | 快(只取值) | 不可直接删除 | | 普通for循环 | ArrayList等支持随机访问的集合 | ArrayList快,LinkedList极慢 | 可删除(需调整索引) | | 增强for循环 | 所有实现了Iterable的集合 | 较快(但比直接迭代器稍慢) | 不可以 | | 迭代器 | 所有集合,尤其是LinkedList | 快(LinkedList必须使用) | 可以(使用remove方法) | 参考文献: [^1]: Java集合篇:Map常用遍历方式以及性能对比 [^2]: Java集合遍历方式及效率对比 [^3]: keySet遍历示例 [^4]: Java集合的几种遍历方式及区别</think>### Java集合遍历方式对比 #### 一、Map集合遍历方式对比 | 遍历方式 | 原理描述 | 性能特点 | 适用场景 | 代码示例 | |-------------------|------------------------------|------------------------------|------------------------------|--------------------------------------------------------------------------| | **keySet遍历** | 先获取所有键集合,再逐个取值 | 效率最低(两次查找操作)[^1] | 只需键名时 | ```java<br>for (K key : map.keySet()) {<br> V value = map.get(key);<br>}<br>``` | | **entrySet遍历** | 直接获取键值对集合 | 效率最高(推荐方式)[^1] | 需要同时访问键和值 | ```java<br>for (Map.Entry<K,V> entry : map.entrySet()) {<br> K key = entry.getKey();<br> V value = entry.getValue();<br>}<br>``` | | **values遍历** | 仅获取值集合 | 效率中等 | 只需值数据时 | ```java<br>for (V value : map.values()) {<br> // 处理值<br>}<br>``` | | **Iterator遍历** | 使用迭代器对象 | 效率接近entrySet | 遍历时需要删除元素 | ```java<br>Iterator<Map.Entry<K,V>> it = map.entrySet().iterator();<br>while (it.hasNext()) {<br> Map.Entry<K,V> entry = it.next();<br> it.remove(); // 安全删除<br>}<br>``` | > **性能实测**(百万级HashMap)[^1]: > - entrySet:120 ms > - keySet:220 ms > - values:180 ms #### 二、Collection遍历方式对比 | 遍历方式 | 实现原理 | 性能特点 | 功能限制 | |-------------------|------------------------------|---------------------------|------------------------------| | **普通for循环** | 基于索引随机访问 | ArrayList极快,LinkedList极慢 | 可修改元素,但删除需调整索引 | | **增强for循环** | 基于迭代器(语法糖)[^2][^4] | 比Iterator略慢(类型转换) | **不可修改集合结构**[^2] | | **Iterator遍历** | 显式使用迭代器对象 | 最优性能[^2] | 可安全删除元素 | | **forEach()** | 内部迭代(Java8+) | 接近Iterator | 不可修改集合 | ```java // ArrayList遍历对比(百万数据) List<String> list = new ArrayList<>(...); // 1. 普通for循环(最快) for (int i = 0; i < list.size(); i++) { String item = list.get(i); } // 2. Iterator遍历(推荐通用方式) Iterator<String> it = list.iterator(); while (it.hasNext()) { String item = it.next(); } // 3. 增强for循环(简洁但性能稍低) for (String item : list) { // 不可执行list.remove(item) } // 4. forEach方法(Java8+) list.forEach(item -> System.out.println(item)); ``` #### 三、核心差异总结 | 特性 | 普通for循环 | 增强for循环 | Iterator | forEach | |---------------------|-------------|-------------|------------|------------| | **随机访问能力** | ✓ | ✗ | ✗ | ✗ | | **遍历中删除元素** | 需调整索引 | ✗(抛异常) | ✓ | ✗ | | **多线程安全** | ✗ | ✗ | 需手动同步 | ✗ | | **链表集合性能** | 极差(O(n²)) | 优(O(n)) | 优(O(n)) | 优(O(n)) | | **代码简洁度** | 中 | 优 | 差 | 优 | #### 四、最佳实践建议 1. **Map遍历**:优先使用`entrySet`,性能最佳[^1] ```java // 推荐方式 for (Map.Entry<K,V> entry : map.entrySet()) { processor.process(entry.getKey(), entry.getValue()); } ``` 2. **需要删除元素**:必须使用`Iterator` ```java Iterator<Item> it = collection.iterator(); while (it.hasNext()) { if (shouldRemove(it.next())) { it.remove(); // 唯一安全删除方式 } } ``` 3. **链表结构(LinkedList)**:禁用普通for循环 ```java // 错误示范(性能灾难) for (int i = 0; i < linkedList.size(); i++) { Item item = linkedList.get(i); // 每次O(n)遍历 } ``` 4. **只读遍历**:Java8+优先使用`forEach` ```java // 简洁且可并行化 collection.stream().forEach(System.out::println); ``` > **性能铁律**: > - ArrayList:普通for循环 ≈ Iterator > 增强for循环 > - LinkedList:Iterator >> 普通for循环(差距可达1000倍)[^2][^4] #### 五、底层原理说明 所有遍历方式都基于`Iterable`接口实现[^4]: ```java public interface Iterable<T> { Iterator<T> iterator(); // 增强for循环的支撑 } ``` 增强for循环编译后实质是迭代器操作: ```java // 源码 for (Item item : collection) { ... } // 编译后等价于 Iterator<Item> it = collection.iterator(); while (it.hasNext()) { Item item = it.next(); ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值