首页 > 代码库 > 集合(下)
集合(下)
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接口
? Deque( Double 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实现类
HashMap是Map最常使用的实现类。
遍历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、LinkedHashMap与TreeMap
LinkedHashMap继承自HashMap。 TreeMap 继承自 AbstractMap。
在特征上与LinkedHashSet与TreeSet类似。
NavigableMap是SortedMap的子接口。
TreeMap是NavigableMap的实现类。
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)); } }
集合(下)