目录
1、Map 的基础操作
2、批量操作 Bulk Operations
3、集合视图 Collection Views
4、Map代数 Map Algebra
Map是一个将键映射到值的对象。map不能包含重复的键,它模拟数学函数的抽象。
Java平台包含三种通用Map实现:HashMap、TreeMap和LinkedHashMap。它们的行为和性能完全类似于HashSet、TreeSet和LinkedHashSet。
例如,Map常见的应用场景,按部门对员工进行分组
// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
或者按部门计算工资总和
// Compute sum of salaries by department
Map<Department, Integer> totalByDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
或者通过及格或不及格来分组学生:
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing = students.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade()>= PASS_THRESHOLD));
甚至同时使用多个条件进行分类:
// Cascade Collectors
Map<String, Map<String, List<Person>>> peopleByStateAndCity
= personStream.collect(Collectors.groupingBy(Person::getState,
Collectors.groupingBy(Person::getCity)))
1、Map 的基础操作
Map的基本操作(put、get、containsKey、containsValue、size和isEmpty)与Hashtable中的对应操作完全相同。
下面的程序统计字符串在参数列表中出现的次数。
public class Freq {
public static void main(String[] args) {
args = "java freq if it is to be it is up to me to delegate".split(" ");
Map<String, Integer> m = new TreeMap<>();
// Initialize frequency table from command line
for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null) ? 1 : freq + 1);
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
}
}
该程序产生以下输出:
10 distinct words:
{delegate=1, java=1, be=1, freq=1, me=1, is=2, it=2, to=3, up=1, if=1}
如果希望看到按字母顺序排列的结果,可以将Map的实现类型从HashMap更改为TreeMap。同一命令行会生成以下输出:
10 distinct words:
{be=1, delegate=1, freq=1, if=1, is=2, it=2, java=1, me=1, to=3, up=1}
同样,将映射的实现类型更改为LinkedHashMap,就可以使程序按照单词在命令行中首次出现的顺序进行打印。同一命令行会产生以下输出:
10 distinct words:
{java=1, freq=1, if=1, it=2, is=2, to=3, be=1, up=1, me=1, delegate=1}
Map 提供的构造函数支持Map对象作为入参:
// 其中入参m,为另一个map
Map<K, V> copy = new HashMap<K, V>(m);
简单的示例程序
import java.util.HashMap;
import java.util.Map;
public class Freq {
public static void main(String[] args) {
Map<String, String> m = new HashMap<>();
m.put("A", "a");
m.put("B", "b");
m.put("C", "c");
Map<String, String> copy = new HashMap<>(m);
for (Map.Entry<String, String> entry : copy.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
2、批量操作 Bulk Operations
clear 从Map中删除所有映射。
putAll 操作Map是对Collection接口addAll操作的模拟。putAll 操作与Map有参构造函数结合使用,为创建带默认值的map提供了一种简洁的方法。下边是演示代码:
static <K, V> Map<K, V> newAttributeMap(Map<K, V>defaults, Map<K, V> overrides) {
Map<K, V> result = new HashMap<K, V>(defaults);
result.putAll(overrides);
return result;
}
3、集合视图 Collection Views
Collection Views 允许通过以下三种方式将Map视为集合:
-
keySet
— Map中包含的键的集合(set 集合)。 -
values
— Map中包含的值的集合。此集合不是Set,因为多个键可以映射到相同的值。 -
entrySet
— Map中包含的键值对的集合。在Map接口中提供了一个嵌套接口Map.Entry
,entrySet
集合中的元素类型就是Entry(键值对)
。
Collection Views 提供了在Map上迭代的方法。下边例子演示了使用for-each在Map中遍历键的标准用法:
for (KeyType key : m.keySet())
System.out.println(key);
使用迭代器
// Filter a map based on some
// property of its keys.
for (Iterator<Type> it = m.keySet().iterator(); it.hasNext(); )
if (it.next().isBogus())
it.remove();
遍历键-值对的标准用法:
for (Map.Entry<KeyType, ValType> e : m.entrySet())
System.out.println(e.getKey() + ": " + e.getValue());
4、Map代数 Map Algebra
在使用集合时,批量操作 containsAll、removeAll和retainAll等,都是非常有效的工具。
在Map中如何实现这一操作?比如,想知道Map a是否包含Map b中的所有键值映射。下边代码实现了这一功能
if (m1.entrySet().containsAll(m2.entrySet())) {
...
}
同样的,如果想知道两个Map对象是否包含相同键的映射。
if (m1.keySet().equals(m2.keySet())) {
...
}
应用场景:如果有一个表示属性-值对的集合的Map,以及两个表示所需属性和允许属性的set。下面的代码将确定属性映射是否符合这些约束,如果不符合,则打印详细的错误消息。
static <K, V> boolean validate(Map<K, V> attrMap, Set<K> requiredAttrs, Set<K> permittedAttrs) {
boolean valid = true;
Set<K> attrs = attrMap.keySet();
if (!attrs.containsAll(requiredAttrs)) { // 检验是否符合约束
Set<K> missing = new HashSet<K>(requiredAttrs); // copy原Map
missing.removeAll(attrs); // 移除掉已经存在的约束
System.out.println("Missing attributes: " + missing); // 打印没有匹配到的约束
valid = false; // 校验失败
}
if (!permittedAttrs.containsAll(attrs)) {
Set<K> illegal = new HashSet<K>(attrs);
illegal.removeAll(permittedAttrs);
System.out.println("Illegal attributes: " + illegal);
valid = false;
}
return valid;
}
如果想知道两个Map对象共有的所有键
Set<KeyType>commonKeys = new HashSet<KeyType>(m1.keySet());
commonKeys.retainAll(m2.keySet()); // 交集
如果想删除一个Map与另一个Map共有的键值对或者键。
m1.entrySet().removeAll(m2.entrySet()); // 删除键值对
m1.keySet().removeAll(m2.keySet()); // 删除键
参考文章:https://docs.oracle.com/javase/tutorial/collections/interfaces/map.html