Map
作为一种 key-value
格式的数据结构在我们的开发过程中经常用到。通过 Map
我们可以对数据数据检索实现接近 O(1) 的时间复杂度。
// 创建一个 Map 对象
Map<Integer,String> map = new HashMap<>(12);
// 往 map 中写入数据
map.put(1,"张三");
map.put(2,"李四");
// 从 map 中读取数据
System.out.println("key: %d value: %s",1,map.get(1));
// key: 1 value: 张三
但是一些 Map 的志向却不仅仅于此,它们为了在更加复杂场景下提供更加简单高效的操作而努力拼搏着,这些 Map 由 guava 工具包提供。
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
集合中的集合 MultiMap<Key,Value>
MultiMap
是一种 value
为 集合(List/Set)
类型的 Map
结构,通过组合数据结构形成了 Map<K, Collecton<V>>
这样集合套集合
的形式。在普通 Map
操作下,我们需要自己构造和判断内集合
操作。比如内集合
是是否存在或者删除一个内集合
,亦或者遍历整个 Map
,这些场景下我们需要基于普通 Map
下实现更多代码来完成这些操作。而 MultiMap
帮助我们封装了这些操作,使得我们对于这类的数据结构的操作变的简单。
// 数集合示例
final ArrayListMultimap<String, Number> numExamples = ArrayListMultimap.create();
numExamples.put("Integer", Integer.MAX_VALUE);
numExamples.put("Integer", Integer.MIN_VALUE);
numExamples.put("Integer", 12);
// 放入浮点数集合
numExamples.put("Float", Float.MAX_VALUE);
numExamples.put("Float", Float.MIN_VALUE);
numExamples.put("Float", Float.MIN_NORMAL);
numExamples.put("Float", Float.MIN_EXPONENT);
// 打印整数集合示例
System.out.println(numExamples.get("Integer"));
可以看到,我们在put(value)
的时候需要像普通 Map
一样先获取 Value
并判断 Value
是否为 ,null
如果为 null
然后新建 list
并将值放入,封装后的 MultiMap
帮助我们做了所有麻烦的操作,让我们能够专注于业务代码:
从上面可以看到 Map<Key,List<Value>>
的实现格式需要我们单独对 List
进行判断,而 MultiMap<Key,Value>
的实现形式则帮助我们封装了这些操作。
英汉互译词典 BidiMap<Key,Value>
BidiMap<Key,Value>
是另一种特殊的 Map
形式,可以实现对 Map
的反向查询。 Map
数据结构本身有点像"词典" 的效果,能够根据 key
帮助我们快速检索对应的内容。而 BidiMap<Key,Value>
更像是一本英汉-汉英
互译的词典,因为它不仅能够帮助我们根据 key
去查找 value
,同时也能够帮助我们根据 value
去查找 key
。
这种"英汉互译"形式的数据结构存在于 Apache Common Collections
包中,在使用前我们需要引入该包。
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
BidiMap<String,String> dictionary = new DualHashBidiMap<>();
dictionary.put("苹果","apple");
dictionary.put("橘子","orange");
dictionary.put("香蕉","banana");
// 根据苹果查 apple
System.out.println(dictionary.get("苹果"));
// 根据 apple 查 苹果
System.out.println(dictionary.getKey("apple"));
注意:BidiMap中key不能重复,value也不可以。
永不放弃 LazyMap
LazyMap
为我们存在但是还没有放入 Map
的值设计了一些特殊的行为,使得我们可以在还没有放入值的时候通过这些行为获取到值。简单来说,普通的 Map
在无法 get
到值的时候会返回 null
,而 LazyMap
会在此时去尝试根据我们制定的行为去获取值。
LazyMap
同样是 Apache Common Collections
中的数据结构,我们需要引入该工具包来进行调用。
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
示例1
// 设计一个记录时间的记录器,当没有获取到改时间的时候返回当前时间
final LazyMap<String, Long> recorder = LazyMap.lazyMap(new HashMap<>(12),
System::currentTimeMillis);
recorder.put("Birthday", 852087816904L);
// lazy 模式,如果没有值则根据方法获取值,这里返回上面 put 的值
System.out.println(recorder.get("Birthday"));
// 返回当前时间
System.out.println(recorder.get("Today"));
// 返回当前时间
System.out.println(recorder.get("Anniversary"));
示例2
// 设计一个记录时间的记录器,当没有获取到改时间的时候返回当前时间
final LazyMap<String, String> recorder = LazyMap.lazyMap(new HashMap<>(12),
str-> str+": "+ System.currentTimeMillis());
recorder.put("Birthday", "1970-1-1");
// lazy 模式,如果没有值则根据方法获取值
System.out.println(recorder.get("Birthday"));
System.out.println(recorder.get("Today"));
System.out.println(recorder.get("Anniversary"));