Java中集合遍历方式(List、Set、Queue、Deque、Stack、Map)

什么是集合?通俗的讲,集合就是存储一组数据的容器,那么,相比较于同样是存储数据的数组,集合的优势就体现在集合的长度是可变的,而数组的长度是固定的。在我们常见的集合中,主要有两大类:

Collection接口单列集合和Map双列集合(键值对集合)接口,其中实现Collection接口的集合主要有:List、Set、Queue(队列),实现Map接口的集合主要是HashMap、LinkedHashMap、TreeMap等。下面分别介绍这些集合是如何来便利的。

List集合(接口)

特点:有序,可重复

主要实现类:ArrayList:内部基于数组,查找元素、遍历集合的速度快

Linkedlist:内部基于链表,插入、删除元素的速度快

以ArrayList为例,遍历集合

        ArrayList<String> list = new ArrayList<String>();

		list.add("小鲁班");
		list.add("貂蝉");
		list.add("后羿");
		list.add("白起");
		list.add("亚瑟");
		list.add("百里守约");       
    
        // 方式1:foreach循环
		for (String hero : list) {
			System.out.print(hero + " ");
		}
		System.out.println();

		// 方式2:for循环
		for (int i = 0; i < list.size(); i++) {
			System.out.print(list.get(i) + " ");
		}
		System.out.println();

		// 方式3:迭代器
		Iterator<String> it = list.iterator();
		while (it.hasNext()) {
			String hero = it.next();
			System.out.print(hero + " ");
		}

        // 运行结果相同
        // 小鲁班 貂蝉 后羿 白起 亚瑟 百里守约 

 Set集合(接口)

特点:无序,元素不可重复,只用使用迭代器和foreach循环遍历

主要实现类:HashSet:内部基于HashMap,无序,元素不可重复

		HashSet<String> set = new HashSet<String>();

		set.add("小鲁班");
		set.add("貂蝉");
		set.add("后羿");
		set.add("白起");
		set.add("亚瑟");
		set.add("百里守约");
		
		// foreach遍历
		for(String s : set) {
			System.out.print(s + " ");
		}

        // 运行结果
        // 白起 貂蝉 小鲁班 百里守约 后羿 亚瑟 

LinkedHashSet:内部基于LinkedHashMap,有序(根据添加的顺序),元素不可重复

		LinkedHashSet<String> set = new LinkedHashSet<String>();

		set.add("小鲁班");
		set.add("貂蝉");
		set.add("后羿");
		set.add("白起");
		set.add("亚瑟");
		set.add("百里守约");
		
		// foreach遍历
		for(String s : set) {
			System.out.print(s + " ");
		}

        // 运行结果
        // 小鲁班 貂蝉 后羿 白起 亚瑟 百里守约 

TreeSet:内部基于TreeMap,可以自动排序(实现Comparable接口和Comparator接口,需要重写compareTo方法,实现排序逻辑,如果添加的元素没有实现Comparable接口,那么需要在构造方法时,传入一个Comparator实现类对象),元素不可重复

	    TreeSet<String> set = new TreeSet<String>();

		set.add("小鲁班");
		set.add("貂蝉");
		set.add("后羿");
		set.add("白起");
		set.add("亚瑟");
		set.add("百里守约");

		// 迭代器
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			String name = it.next();
			System.out.print(name + " ");
		}
    
        // 运行结果
        // 亚瑟 后羿 小鲁班 白起 百里守约 貂蝉 

Queue队列(接口)

特点:线性表结构,遵循先进先出(FIFO)原则,一般来说,只允许在集合前端进行出队操作,在集合后端进行入队操作

遍历方式:foreach循环遍历、迭代器遍历、while循环判空遍历

有界队列:队列容量受构造方法的容量参数限制,主要实现类:ArrayBlockingQueue,超出容量限制时,会抛出IllegalStateException异常

无界队列:队列容量没有限制,主要实现类:LinkedList

优先级队列:添加的元素必须实现Comporable接口,如果没有实现,必须在构造方法时传入一个Comparator实现类对象,内部通过用数组表示的小顶堆实现,队首永远是优先级最高(根据重写的comparTo方法实现的逻辑排序)的元素

以优先级队列为例

		Queue<String> queue = new PriorityQueue<String>();
		
		queue.offer("C");
		queue.offer("B");
		queue.offer("D");
		queue.offer("A");
		queue.offer("E");
		
		// foreach遍历
		for(String s : queue) {
			System.out.print(s+" ");
		}
		
		System.out.println();
		
		// 迭代器遍历
		Iterator<String> it = queue.iterator();
		while (it.hasNext()) {
			String s = it.next();
			System.out.print(s + " ");
		}

        System.out.println();

        // 运行结果相同
        // A B D C E 
		
		// 使用isEmpty()方法对队列进行判空,然后出队遍历
		while(!queue.isEmpty()) {
			System.out.print(queue.poll() + " ");
		}

        // 由于优先级不同,运行结果与上面不同
        // A B C D E 

Deque双端队列(接口)

特点:线性表结构,相比于Queue可在集合两端进行出队、入队操作

遍历方式:foreach循环遍历、迭代器遍历、while循环判空遍历

Queue与Deque比较
        QueueDeque
添加元素到队尾add(E e) / offer(E e)addLast(E e) / offerLast(E e)
取首元素并删除E remove() / E poll()E removeFirst() / E pollFirst()
取首元素并不删除E element() / E peek()E getFirst / E peekFirst()
添加元素到队首addFirst(E e) / offerFirst(E e)
取队尾元素并删除E removeLast() / E pollLast()
取队尾元素但不删除E getLast / E peekLast()
		Deque<String> deque = new LinkedList<String>();
		
		deque.offer("A"); // 队尾
		deque.offerFirst("V"); // 队头
		deque.offer("S"); // 队尾
		deque.offerLast("G");
		deque.offer("E");
		
		System.out.println(deque);

        // 运行结果
        // [V, A, S, G, E]

        // 迭代器
		Iterator<String> it = deque.iterator();
		while (it.hasNext()) {
			String s = it.next();
			System.out.print(s + " ");
		}

     	// foreach循环
		for (String s : deque) {
			System.out.print(s + " ");
		}

        // 运行结果
        // V A S G E 

注意:以下两种方法只能单独使用,当遍历时,由于使用了poll()方法,队列中的元素已经出队,当出队完毕时,队列中已经没有元素,需要再次入队才能进行下一次操作。

		// 从队首开始遍历并出队
		String item = null;
		while((item = deque.pollFirst())!= null) {
			System.out.print(item + " ");
		}
        
        // 运行结果
        // V A S G E 
		// 从队尾开始遍历并出队
		String item = null;
		while((item = deque.pollLast())!= null) {
			System.out.print(item + " ");
		}

        // 运行结果
        // E G S A V 

Stack栈(

特点:后进先出(LIFO),只有入栈和出栈操作

遍历方式:foreach循环遍历、迭代器遍历、while循环判空遍历

Stack继承自Vector类,而Vector实现了List接口,由于Vector的方法都是同步的(Synchronized),是线程安全的,而与之类似的ArrayList的方法不是同步的,因此,ArrayList的性能会比Vector好。

压栈push(E e)
把栈顶元素弹出E pop()
取出栈顶元素但不弹出E peek()
	    Stack<String> stack = new Stack<String>();
		
		stack.push("A1");
		stack.push("A2");
		stack.push("A3");
		stack.push("A4");
		stack.push("A5");
		
		// foreach
		for(String s : stack) {
			System.out.print(s + " ");
		}
		
		System.out.println();
		
		// 迭代器
		Iterator<String> it = stack.iterator();
		while (it.hasNext()) {
			String s = it.next();
			System.out.print(s + " ");
		}
		
		System.out.println();
		
		// 遍历并出栈
		while(!stack.isEmpty()) {
			System.out.print(stack.pop() + " ");
		}

        // 运行结果
        // A1 A2 A3 A4 A5 
        // A1 A2 A3 A4 A5 
        // A5 A4 A3 A2 A1 

由于栈是后进先出原则,在pop时,会先弹出栈顶元素,也就是最后入栈的元素,因此运行结果与前两种不同。

Map集合

特点:键值对集合,映射表,键唯一,值不唯一,一个键可以对应多个值,可以通过键快速查找值

遍历方式:foreach循环遍历KeySet()、foreach循环遍历entrySet()

主要实现类:HashMap:数据结构采用数组+链表+红黑树,数组类型为Node[],每个Node都保存了某个KV键值对的key、value、hash、next等值,当添加新元素时,会按照key的hash值与它的高16位进行异或运算((n-1)^hash),计算数组中的存储位置下标,如果该下标位置已经存在元素,代表哈希冲突,则采用链地址法存储到链表尾部,当链表Node节点数量大于8,如果当数组长度大于64时,会将链表转换成一个红黑树。当数组长度小于64时,就会进行数组扩容,扩容容量是当前容量的2倍;同时如果hashMap中的元素个数达到扩容阈值(数组容量(默认为16)*加载因子(默认为0.75))时,也会进行扩容。

	    HashMap<String, Integer> map = new HashMap<String, Integer>();

		map.put("apple", 5);
		map.put("banana", 9);
		map.put("orange", 15);
		map.put("pear", 7);

		// foreach循环遍历KeySet()
		for (String key : map.keySet()) {
			Integer value = map.get(key);
			System.out.print(key + ":" + value + " ");
		}

		System.out.println();
		
		// foreach循环遍历entrySet()
		for (Entry<String, Integer> e : map.entrySet()) {
			String key = e.getKey();
			Integer value = e.getValue();
			System.out.print(key + ":" + value + " ");
		}

        // 运行结果相同
        // banana:9 orange:15 apple:5 pear:7 

LinkedHashMap:HashMap的子类,有序,遍历时顺序与添加顺序相同

        LinkedHashMap<String, Integer> map = new LinkedHashMap<String, Integer>();

		map.put("apple", 5);
		map.put("banana", 9);
		map.put("orange", 15);
		map.put("pear", 7);

		// foreach循环遍历KeySet()
		for (String key : map.keySet()) {
			Integer value = map.get(key);
			System.out.print(key + ":" + value + " ");
		}

		System.out.println();
		
		// foreach循环遍历entrySet()
		for (Entry<String, Integer> e : map.entrySet()) {
			String key = e.getKey();
			Integer value = e.getValue();
			System.out.print(key + ":" + value + " ");
		}

        // 运行结果相同
        // apple:5 banana:9 orange:15 pear:7 

TreeMap:实现了SortedMap接口,可以自动按照排序规则排序,key必须实现Comparable接口或Comparator接口,需要重写compareTo方法,实现排序逻辑,如果添加的元素没有实现Comparable接口,那么需要在构造方法时,传入一个Comparator实现类对象

import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

public class Test {
	public static void main(String[] args) {
        Map<Person, Integer> map = new TreeMap<Person, Integer>(new Comparator<Person>() {

			@Override
			public int compare(Person o1, Person o2) {
				return o1.name.compareTo(o2.name);
			}
		});
        map.put(new Person("Tom"), 90);
        map.put(new Person("Bob"), 76);
        map.put(new Person("Lily"), 59);
        
		// foreach循环遍历KeySet()
		for (Person key : map.keySet()) {
			Integer value = map.get(key);
			System.out.print(key + ":" + value + " ");
		}

		System.out.println();
		
		// foreach循环遍历entrySet()
		for (Entry<Person, Integer> e : map.entrySet()) {
			Person key = e.getKey();
			Integer value = e.getValue();
			System.out.print(key + ":" + value + " ");
		}

        // 运行结果相同
        // Person [name=Bob]:76 Person [name=Lily]:59 Person [name=Tom]:90 
        
    }
}

class Person {
    public String name;
    Person(String name) {
        this.name = name;
    }
	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}


版权声明:本文为qq_45958440原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。