首页 > 代码库 > 集合(下)

集合(下)

1、Queue接口
Queue接口是Collection接口的子接口。
Queue接口表示一个队列,分为队头与队尾。通常实现先进 先出的原则( FIFO),但这不是必须的。
例如,
PriorityQueue是根据优先级来进行排序的。队列会根据具体的实现来组织与管理新加入元素的位置。无论 哪种实现方式,删除(获取)元素时,会删除(获取)队 列头部的元素。

package day15;

import java.util.LinkedList;
import java.util.Queue;

/*
 * Queue接口
 * 接口中的方法可以分成两组:
 * 一组:add   remove    element
 * 二组:offer poll		peek
 * 第一组在操作失败时,会产生异常。
 * 第二组在操作失败时,不会产生异常,而是返回特定的值。
 * 优先考虑使用第二组方法。
 * 
 * Queue接口关于null值。
 * Queue接口中不允许加入null值。因为null值是作为poll与peek
 * 在操作失败时的返回值。
 * 对于LinkedList实现类,允许加入null值,这是一种特例,因为
 * 要做到兼容以前的程序。(我们要尽可能回避这种特例)
 */
public class QueueMethod {

	public static void main(String[] args) {
		Queue<Integer> q = new LinkedList<>();
		// 向队列中加入元素。如果加入失败,抛出异常。
		q.add(1);
		// 向队列中加入元素。如果加入失败,返回false。
		// (不会产生异常。)
		q.offer(1);
		// 删除并返回队列头部的元素。如果删除失败,抛出异常。
		// q.remove();
		// 删除并返回队列头部的元素。如果删除失败,返回null。
		// q.poll();
		// 获取并返回队列头部的元素(不会删除该元素)。如果
		// 获取失败,抛出异常。
		// q.element();
		// 获取并返回队列头部的元素(不会删除该元素)。如果
		// 获取失败,返回null。
		// q.peek();
		// 一种特例。
		q.add(null);

	}

}

  2、PriorityQueue实现类
Queue接口的一个特殊的实现类,不是按照先进先出的原则, 而是根据特定机制对元素进行排序处理。排序的规则可能是:
? 自然排序
? 指定排序
说明:
? PriorityQueue实现类没有元素的限制。
? PriorityQueue对内部元素的排序不会体现在集合的遍历上。

/*
 * PriorityQueue优先级队列
 */
package day15;

import java.util.PriorityQueue;
import java.util.Queue;

/*
 * PriorityQueue是Queue的一个特殊实现类,其不是按照
 * 传统的先进先出的原则实现的,而是按照元素的优先级在内部
 * 进行排序。注意:内部的元素排序不会表现在元素的遍历上。
 * 
 * 对于无参的构造器,使用自然排序。
 * 也可以传递一个比较器。
 */
public class PriorityQueueTest {

	public static void main(String[] args) {
		// Queue<Integer> q = new PriorityQueue<>();
		Queue<Integer> q = new PriorityQueue<>((a, b) -> b - a);
		// q.add(null);
		q.offer(100);
		q.offer(20);
		q.offer(15);
		q.offer(68);
		// 在使用PriorityQueue对元素进行遍历时,
		// 不保证任何遍历顺序(遍历顺序没有任何保证)。
		// q.forEach(System.out::println);
		while (q.size() > 0) {
			System.out.println(q.poll());
		}
	}

}

  3、Deque接口
? DequeDouble Ended Queue)接口是Queue接口的子接口。
? Deque接口表示一个双端的队列,即可以从队列的两端增加 与删除(获取)元素。
? Deque接口可以同时实现队列( FIFO)与堆栈( LIFO)的功 能。

Deque接口有两个常用的实现类:
? ArrayDeque
? LinkedList

package day15;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;

public class DequeMethod {

	public static void main(String[] args) {
		// Deque<Integer> dq = new LinkedList<>();
		Deque<Integer> dq = new ArrayDeque<>();
		// 从队头加入元素。失败时会产生异常。
		dq.addFirst(1);
		// 从队尾加入元素。
		dq.addLast(1);
		// 从队头加入元素。失败时不会产生异常,而是返回false。
		dq.offerFirst(1);
		// 从队尾加入元素。
		dq.offerLast(1);
		// 删除并返回队列头部的元素。
		dq.removeFirst();
		// 删除并返回队列尾部的元素。
		dq.removeLast();
		// 删除并返回队列头部的元素。失败时不会产生异常,而是返回null。
		dq.pollFirst();
		// 删除并返回队列尾部的元素。失败时不会产生异常,而是返回null。
		dq.pollLast();
		// 获取队列头部的元素(不会删除该元素)。
		dq.getFirst();
		// 获取队列尾部的元素(不会删除该元素)。
		dq.getLast();
		// 获取队列头部的元素(不会删除该元素)。失败时不会产生
		// 异常,而是返回null。
		dq.peekFirst();
		// 获取队列尾部的元素(不会删除该元素)。失败时不会产生
		// 异常,而是返回null。
		dq.peekLast();
		// 删除队列中首次出现的元素(参数指定)。删除成功返回true,
		// 否则返回false。
		dq.removeFirstOccurrence(2);
		// 删除队列中最后一次出现的元素(参数指定)。删除成功返回true,
		// 否则返回false。
		dq.removeLastOccurrence(1);
		// 向队列头部加入元素。(作为堆栈使用)
		dq.push(1);
		// 删除队列头部的元素。(作为堆栈使用)
		dq.pop();
	}

}

  4、Map接口

package day15;

import java.util.HashMap;
import java.util.Map;

public class MapTest {
	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<>();
		// 加入键值对,返回该键之前绑定的值。如果该键之前没有
		// 绑定值,则返回null。
		System.out.println(map.put(1, "abc"));
		// map中的键值不能重复,如果加入了重复了键值,
		// 则该键值会绑定后来的value。
		System.out.println(map.put(1, "cdf"));
		// 获取键(key)绑定的值(value)
		System.out.println(map.get(1));
	}
}

  5、HashMap实现类
HashMapMap最常使用的实现类。
遍历Map的方式: 使用keyset    使用entrySet    使用forEach 

package day15;

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

public class MapMethod {

	public static void main(String[] args) {
		Map<Integer, Integer> map = new HashMap<>();
		map.put(1, 100);
		map.put(2, 200);
		// 返回map中键值对的数量。
		// System.out.println(map.size());
		// 判断map是否为空(键值对数量是否为0),
		// 如果为空,返回true,否则返回false。
		// System.out.println(map.isEmpty());
		// 判断map中是否含有参数指定的key。含有返回true,
		// 否则返回false。
		// System.out.println(map.containsKey(1));
		// 判断map中是否含有参数指定的value。含有返回true,
		// 否则返回false。
		// System.out.println(map.containsValue(200));
		// 删除与参数指定键值相等的键值对。返回该键所绑定
		// 的value值。如果该键没有绑定value值,返回null。
		// System.out.println(map.remove(10));
		Map<Integer, Integer> map2 = new HashMap<>();
		map2.put(3, 300);
		map2.put(4, 400);
		// 将参数map中所有的键值对加入到当前map中。
		map.putAll(map2);
		// System.out.println(map);
		// 清空map。(删除map中所有的键值对)
		// map.clear();
		System.out.println(map);
		// 返回一个set,该set中包含map中所有的key值。
		Set<Integer> set = map.keySet();
		// set.forEach(System.out::println);
		// 返回一个Collection,该Collection中包含
		// map中所有的value值。
		Collection<Integer> c = map.values();
		// c.forEach(System.out::println);
		// 返回一个set,该set中存放map中所有的Entry(键值对)。
		Set<Entry<Integer, Integer>> entrys = map.entrySet();
	}

}

  

package day15;

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

/*
 * 对Map进行遍历
 */
public class MapTraverse {

	public static void main(String[] args) {
		Map<Integer, Integer> map = new HashMap<>();
		map.put(1, 100);
		map.put(2, 200);
		map.put(3, 300);
		map.put(4, 500);
		// 1 使用keySet方法。
		Set<Integer> keys = map.keySet();
		keys.forEach(k -> System.out.println(k + ":" + map.get(k)));
		// 2使用entrySet方法
		Set<Entry<Integer, Integer>> entry = map.entrySet();
		entry.forEach(e -> System.out.println(e.getKey() + ":" + e.getValue()));
		map.forEach((k, v) -> System.out.println(k + ":" + v));
	}
}

  6、LinkedHashMapTreeMap
LinkedHashMap继承自HashMapTreeMap 继承自 AbstractMap
在特征上与LinkedHashSetTreeSet类似。
NavigableMapSortedMap的子接口。
TreeMapNavigableMap的实现类。

package day15;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapTest {

	public static void main(String[] args) {
		// Map<String, Integer> map = new HashMap<>();
		Map<String, Integer> map = new LinkedHashMap<>();
		map.put("addf", 11);
		map.put("zdfeaa", 22);
		map.put("fous", 33);
		map.put("onensdf", 44);
		map.put("tisoe", 55);
		/*
		 * 与HashSet相同,HashMap在获取元素时,也不能保证 获取的顺序与元素加入时的顺序一致。实际上,HashSet
		 * 底层就是使用HashMap来实现的。 如果期望获取元素的顺序与元素加入时的顺序一致,可以使用 LinkedHashMap来实现。
		 */
		map.forEach((k, v) -> System.out.println(k + ":" + v));
	}

}

 

package day15;

import java.util.Map;
import java.util.TreeMap;

public class TreeMapTest {
	public static void main(String[] args) {
		// TreeMap是根据key值进行排序的。
		// Map<Integer, String> map = new TreeMap<>();
		Map<Integer, String> map = new TreeMap<>((a, b) -> b - a);
		// 可以指定比较器,如果没有提供比较器,则使用自然排序。
		map.put(1, "sdf");
		map.put(5, "ccc");
		map.put(-2, "csa");
		map.forEach((k, v) -> System.out.println(k + ":" + v));
	}
}

  7、聚合操作
流是一组元素的序列。集合对象可以通过相关方法获得流。
通过集合对象的流,就可以在流的基础上对集合元素进行相 关的操作,如过滤,映射,迭代等,该操作称为流操作,也 称为聚合操作。
流管道为一系列顺序的聚合操作。管道由数据源(数组,集 合, IO通道等), 中间操作( 0或多个)与终端操作( 1个) 组成 
聚合操作可以分为中间操作与终端操作。
? 聚合操作聚合操作的中间操作会产生一个新的流,供后续中 间操作或终端操作使用。而终端操作不会再产生流。
? 中间操作是惰性的,这样可以在一定程度上提高性能。流只 有在终端操作开始时才会执行。
? 中间操作可以分为有状态操作与无状态操作。
? 一旦执行终端操作,则整个流被消费掉,不可再次使用。

 8、案例

输出集合中所有的元素,可以使用:
? forEach方法
? 聚合操作的forEach操作。


package day15;

import java.util.ArrayList;
import java.util.Collection;

public class ForEach {
	public static void main(String[] args) {
		Collection<Integer> c = new ArrayList<>();
		for (int i = 0; i < 50; i++) {
			c.add(i);
		}
		// c.forEach(System.out::println);
		// c.stream().forEach(System.out::println);
		// c.stream().filter(t -> t > 3).forEach(System.out::println);
		// c.forEach(System.out::println);
		// c.stream().forEach(System.out::println);
		c.parallelStream().forEach(System.out::println);
	}
}

  9、聚合操作与迭代器
不同之处:
? 聚合操作从流中处理数据,其不会改变底层的数据源。而迭 代器则对集合进行操作,会改变集合。
? 聚合操作使用内部迭代方式,而迭代器使用外部迭代进行处 理。
? 聚合操作(内部迭代)可以根据需要并行处理数据,而迭代 器仅能进行顺序迭代 
    10、中间操作

中间操作
? filter
? map / mapToInt / mapToLong / mapToDouble
? distinct
? sorted
? peek
? limit
? skip

 11、缩减操作
将流中的内容合并,作为一个值返回,这种操作成为缩减操作。
缩减操作如下:
? max
? min
? average
? sum
? count

? reduce
? collect

说明:缩减操作都是终端操作。 

package day15;

import java.util.*;

public class AggOP {
	public static void main(String[] args) {
		Collection<Integer> c = new ArrayList<>();
		c.add(200);
		c.add(-2);
		c.add(16);
		c.add(28);
		c.add(-2);
		// c.stream().filter(t -> t > 20).forEach(System.out::println);
		// c.stream().distinct().forEach(System.out::println);
		// c.stream().filter(t -> t >
		// 20).distinct().sorted().forEach(System.out::println);
		// c.stream().peek(System.out::println).forEach(System.out::println);
		// c.stream().limit(30).forEach(System.out::println);
		// c.stream().skip(2).forEach(System.out::println);

		Collection<Person> cp = new ArrayList<>();
		cp.add(new Person("1", 20));
		cp.add(new Person("2", 10));
		cp.add(new Person("3", 14));
		cp.add(new Person("4", 24));
		cp.add(new Person("1", 20));
		// cp.stream().map(p -> p.getName()).forEach(System.out::println);
		// cp.stream().map(p -> p.getAge()).forEach(System.out::println);
		// cp.stream().mapToInt(p -> p.getAge()).forEach(System.out::println);
		// cp.stream().distinct().forEach(System.out::println);
		int max = cp.stream().mapToInt(Person::getAge).max().getAsInt();
		int min = cp.stream().mapToInt(Person::getAge).min().getAsInt();
		double avg = cp.stream().mapToInt(Person::getAge).average().getAsDouble();
		int sum = cp.stream().mapToInt(Person::getAge).sum();
		long count = cp.stream().mapToInt(Person::getAge).count();
		// System.out.println(max);
		// System.out.println(min);
		// System.out.println(avg);
		// System.out.println(sum);
		// System.out.println(count);
		// int x =
		// cp.stream().mapToInt(Person::getAge).reduce(Math::max).getAsInt();
		// int x =
		// cp.stream().mapToInt(Person::getAge).reduce(Integer::sum).getAsInt();
		// int x = cp.stream().mapToInt(Person::getAge).reduce(100, Math::max);
		// System.out.println(x);
		// List<Integer> list = cp.stream().filter(p -> p.getAge() >
		// 15).mapToInt(p -> p.getAge()).distinct().sorted()
		// .collect(() -> new ArrayList<>(), (t, e) -> t.add(e), (a, b) ->
		// a.addAll(b));
		List<Integer> list = cp.stream().filter(p -> p.getAge() > 15).mapToInt(p -> p.getAge()).distinct().sorted()
				.collect(ArrayList::new, List::add, List::addAll);
		list.forEach(System.out::println);
	}
}

class Person {
	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

}

  12、Arrays
? Arrays类是一个工具类,提供对数组的一系列操作。
? Arrays类的排序方法( sort)也可以使用自然排序,也可以 指定排序规则。
? asList方法

package day15;

import java.util.Arrays;
import java.util.List;

public class AsList {

	public static void main(String[] args) {
		int[] x = { 1, 2, 3, 5, 8 };
		List<int[]> list = Arrays.asList(x);
		System.out.println(list.size());
		Integer[] y = { 1, 2, 3, 5, 8 };
		List<Integer> list2 = Arrays.asList(y);
		System.out.println(list2.size());
		// 通过asList方法返回的List是不能改变的。
		// 因为数组长度是不能改变的。
		// list2.add(100);
	}

}

  13、Collections
Collections类提供了一系列操作集合的方法。所有的方法都是 静态的。
? sort
? binarySearch
? reverse
? shuffle
? fill
? min / max
? frequency

package day15;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionsMethod {

	public static void main(String[] args) {
		List<Integer> list = new ArrayList<>();
		list.add(500);
		list.add(-20);
		list.add(78);
		list.add(222);
		list.add(78);
		// 对List进行排序(自然排序)。
		// Collections.sort(list);
		// 对List进行排序(比较器)。
		// Collections.sort(list, (a, b) -> b - a);
		// 对于排序,List本身也能够进行排序
		// list.sort(null);
		// list.sort((a, b) -> b - a);
		// list.forEach(System.out::println);
		// 在List中查询指定的关键字,如果找到,返回关键字的
		// 索引,如果没有找到,返回-插入点-1。
		// 要求:List必须是升序排列的,否则结果是不确定的。
		// int index = Collections.binarySearch(list, 333);
		// System.out.println(index);
		// 对List的顺序实现翻转。
		// Collections.reverse(list);
		// list.forEach(System.out::println);
		// 对List进行洗牌操作。
		// Collections.shuffle(list);
		// list.forEach(System.out::println);
		// 使用参数指定的元素对List进行填充。
		// Collections.fill(list, 90);
		// list.forEach(System.out::println);
		// 返回集合中的最大值(自然排序)
		// int x = Collections.max(list);
		// System.out.println(x);
		// 返回集合中的最大值(比较器)
		// int x = Collections.max(list, (a, b) -> b - a);
		// System.out.println(x);
		// 返回集合中的最小值(自然排序)
		// System.out.println(Collections.min(list));
		// 返回集合的最小值(比较器)
		// System.out.println(Collections.min(list, (a, b) -> b - a));
		// 返回关键字(第2个参数)在集合中(第1个参数)出现的频率。
		System.out.println(Collections.frequency(list, 78));
	}

}

  


 

集合(下)