8.6 Java 8增强的Map集合

8.6 Java 8增强的Map集合

Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value,keyvalue都可以是任何引用类型的数据。

Map的key不可重复

Mapkey不允许重复,即同一个Map对象的任何两个key通过equals()方法比较总是返回false

一个key对应一个value

keyvalue之间存在单向一对一关系,即通过指定的key,总能找到唯一的、确定的value

根据key来获取value

Map中取出数据时,只要给出指定的key,就可以取出对应的value

如果把Map的两组值拆开来看,Map里的数据有如图8.7所示的结构。

这里有一张图片

Map中的所有key可以看成一个Set集合

从图8.7中可以看出,如果把Map里的所有key放在一起来看,它们就组成了一个Set集合(所有的key没有顺序,keykey之间不能重复)。

keySet()方法

实际上Map确实包含了一个keySet()方法,用于返回Map里所有key组成的Set集合。

方法 描述
Set<K> keySet() Returns a Set view of the keys contained in this map.

不仅如此,Mapkey集和Set集合里元素的存储形式也很像,Map子类和Set子类在名字上也惊人地相似,比如Set接口下有HashSetLinkedHashSetSortedSet(接口)、 TreeSetEnumSet等子接口和实现类,而Map接口下则有HashMapLinkedHashMapSortedMap(接口)、 TreeMapEnumMap等子接口和实现类。正如它们的名字所暗示的,Map的这些实现类和子接口中key集的存储形式和对应Set集合中元素的存储形式完全相同。

提示

SetMap之间的关系非常密切。虽然Map中放的元素是key-value对,Set集合中放的元素是单个对象,但如果把key-value对中的value当成key的附庸:key在哪里, value就跟在哪里。这样就可以像对待Set一样来对待Map了。事实上,Map提供了一个Entry内部类来封装key-value对,而计算Entry存储时则只考虑Entry封装的key

Map接口的内部接口Entry 描述
static interface Map.Entry<K,​V> A map entry (key-value pair).

Java使用Map来实现Set

Java源码来看,Java是先实现了Map,然后通过包装一个所有value都为nullMap就实现了Set集合

Map中的的所有value可以看成一个List集合

如果把Map里的所有value放在一起来看,它们又非常类似于一个List

  • 元素与元素之间可以重复,每个元素可以根据索引来查找,只是Map中的索引不再使用整数值,而是以另一个对象作为索引。
  • 如果需要从List集合中取出元素,则需要提供该元素的数字索引;
  • 如果需要从Map中取出元素,则需要提供该元素的key索引。

因此,Map有时也被称为字典,或关联数组

Map接口方法

Map接口中定义了如下常用方法。

添加元素的方法

方法 描述
V put(K key, V value) 添加一个key-value对,如果当前Map中已有一个与该key相等的key-value对,则新的key-value对会覆盖原来的key-value对。
void putAll(Map<? extends K,? extends V> m) 将指定Map中的key-value对复制到当前Map中。

查询方法

方法 描述
Object get(Object key) 返回指定key所对应的value;如果此Map中不包含该key,则返回null
int size() 返回该Map里的key-value对的个数。

删除元素的方法

方法 描述
V remove(Object key) 删除指定key所对应的key-value对,返回被删除key所关联的value,如果该key不存在,则返回null
default boolean remove(Object key, Object value) 这是Java8新增的方法,删除指定keyvalue所对应的key-value对。如果从该Map中成功地删除该key-value对,该方法返回true,否则返回false
void clear() 删除该Map对象中的所有key-value对.

判断方法

方法 描述
boolean isEmpty() 查询该Map是否为空(即不包含任何key-value对),如果为空则返回true
boolean containsKey(object key) 查询Map中是否包含指定的key,如果包含则返回true
boolean containsValue(Object value) Returns true if this map maps one or more keys to the specified value.

返回集合

方法 描述
Set keySet() 返回该Map中所有key组成的Set集合。
Set entrySet() 返回Map中包含的key-value对所组成的Set集合,每个集合元素都是 Map.Entry对象(EntryMap的内部类)。
Collection values() 返回该Map里所有 value组成的 Collection

Map的实现类

Map接口提供了大量的实现类,典型实现如HashMapHashtable等、 HashMap的子类LinkedHashMap,还有SortedMap子接口及该接口的实现类TreeMap,以及WeakHashMapIdentityHashMap等。下面将详细介绍Map接口实现类。

Map的内部类Entry

Map中包括一个内部类Entry,该类封装了一个key-value对。 Entry包含如下三个方法。

Mapt.Entry内部接口的方法 描述
K getKey() 返回该Entry里包含的key值。
V getValue() 返回该Entry里包含的value值。
V setValue(V value) 设置该Entry里包含的value值,并返回新设置的value值。

Map集合最典型的用法就是成对地添加删除 key-value对,接下来即可判断该Map中是否包含指定key,是否包含指定value,也可以通过Map提供的keySet()方法获取所有key组成的集合,进而遍历Map中所有的key-value对。

程序 Map接口基本用法

下面程序示范了Map的基本功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.util.*;

public class MapTest
{
public static void main(String[] args)
{
Map map = new HashMap();
// 成对放入多个key-value对
map.put("疯狂Java讲义" , 109);
map.put("疯狂iOS讲义" , 10);
map.put("疯狂Ajax讲义" , 79);
// 多次放入的key-value对中value可以重复
map.put("轻量级Java EE企业应用实战" , 99);
// 放入重复的key时,新的value会覆盖原有的value
// 如果新的value覆盖了原有的value,该方法返回被覆盖的value
System.out.println(map.put("疯狂iOS讲义" , 99)); // 输出10
System.out.println(map); // 输出的Map集合包含4个key-value对
// 判断是否包含指定key
System.out.println("是否包含值为 疯狂iOS讲义 key:"
+ map.containsKey("疯狂iOS讲义")); // 输出true
// 判断是否包含指定value
System.out.println("是否包含值为 99 value:"
+ map.containsValue(99)); // 输出true
// 获取Map集合的所有key组成的集合,通过遍历key来实现遍历所有key-value对
for (Object key : map.keySet() )
{
// map.get(key)方法获取指定key对应的value
System.out.println(key + "-->" + map.get(key));
}
map.remove("疯狂Ajax讲义"); // 根据key来删除key-value对。
System.out.println(map); // 输出结果不再包含 疯狂Ajax讲义=79 的key-value对
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
{疯狂Ajax讲义=79, 疯狂iOS讲义=99, 轻量级Java EE企业应用实战=99, 疯狂Java讲义=109}
是否包含值为 疯狂iOS讲义 key:true
是否包含值为 99 value:true
疯狂Ajax讲义-->79
疯狂iOS讲义-->99
轻量级Java EE企业应用实战-->99
疯狂Java讲义-->109
{疯狂iOS讲义=99, 轻量级Java EE企业应用实战=99, 疯狂Java讲义=109}

上面程序中先示范了向Map中成对地添加key-value对。添加key-value对时,Map允许多个value重复,但如果添加key-value对时Map中已有重复的key,那么新添加的value会覆盖该key原来对应的value并返回被覆盖的value

程序接下来的代码分别判断了Map集合中是否包含指定的key、是否包含指定的value

使用foreach循环 遍历Map集合

程序中的foreach循环用于遍历Map集合:

  • 先调用Map集合的keySet()获取包含所有key的Set集合,
  • 然后使用foreach循环来遍历这个Set集合中的key,
  • 最后根据key来获取对应的value

所有的Map实现类都重写了toString()方法,调用Map对象的toString()方法总是返回如下格式的字符串:{key1=value,key2=value2…}.