MultiMap、BidiMap及LazyMap的使用
一、MultiMap
在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业务逻辑处理。
但是像Map<String, List<StudentScore>> StudentScoreMap = new HashMap<String, List<StudentScore>>()这样的数据结构,自己实现起来太麻烦,你需要检查key是否存在,不存在时则创建一个,存在时在List后面添加上一个。这个过程是比较痛苦的,如果你希望检查List中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么则需要更多的代码来实现。
Guava的Multimap就提供了一个方便地把一个键对应到多个值的数据结构。让我们可以简单优雅的实现上面复杂的数据结构,让我们的精力和时间放在实现业务逻辑上,而不是在数据结构上,下面我们具体来看看Multimap的相关知识点。
上面的代码和数据结构用Multimap来实现,代码结构清晰简单了很多吧,具体代码如下:
/****
* 所谓MultiMap,就是说一个key不在是简单的指向一个对象,而是一组对象,
* add()和remove()的时候跟普通的Map无异,只是在get()时返回一个Collection,
* 利用MultiMap,我们就可以很方便的往一个key上放数量不定的对象,也就实现了一对多。
*/ public class MutliMapTest {
public static void main(String... args) {
Multimap<String, String> myMultimap = ArrayListMultimap.create(); // Adding some key/value
myMultimap.put("Fruits", "Bannana");
myMultimap.put("Fruits", "Apple");
myMultimap.put("Fruits", "Pear");
myMultimap.put("Vegetables", "Carrot"); // Getting the size
int size = myMultimap.size();
System.out.println(size); // 4 // Getting values
Collection<string> fruits = myMultimap.get("Fruits");
System.out.println(fruits); // [Bannana, Apple, Pear] Collection<string> vegetables = myMultimap.get("Vegetables");
System.out.println(vegetables); // [Carrot] // Iterating over entire Mutlimap
for(String value : myMultimap.values()) {
System.out.println(value);
} // Removing a single value
myMultimap.remove("Fruits","Pear");
System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear] // Remove all values for a key
myMultimap.removeAll("Fruits");
System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!) List<String> list = new ArrayList<String>();
List<String> valuelist = new ArrayList<String>();
list.add("123");
list.add("456");
list.add("789");
MultiMap multiMap = new MultiHashMap();
multiMap.put("Sean", list);
multiMap.put("Sean", "C/C++");
multiMap.put("Sean", "OO");
multiMap.put("Sean", "Java");
multiMap.put("Sean", ".NET");
multiMap.remove("Sean", "C/C++");
System.out.println("Sean's skill set: " + multiMap.get("Sean"));
Iterator itet = ((Collection) multiMap.get("Sean")).iterator();
while(itet.hasNext())
{
Object obj = itet.next();
if(obj instanceof List)
{
valuelist = (List<String>)obj;
for(Object value:valuelist)
{
System.out.println("obj1:"+value);
}
}else if(obj instanceof String)
{
System.out.println("value:"+obj.toString());
}
} }
}
Multimap也支持一系列强大的视图功能:
1、asMap把自身Multimap<K, V>映射成Map<K, Collection<V>>视图。这个Map视图支持remove和修改操作,但是不支持put和putAll。严格地来讲,当你希望传入参数是不存在的key,而且你希望返回的是null而不是一个空的可修改的集合的时候就可以调用asMap().get(key)。(你可以强制转型asMap().get(key)的结果类型-对SetMultimap的结果转成Set,对ListMultimap的结果转成List型-但是直接把ListMultimap转成Map<K, List<V>>是不行的。)
2、entries视图是把Multimap里所有的键值对以Collection<Map.Entry<K, V>>的形式展现。
3、keySet视图是把Multimap的键集合作为视图
4、keys视图返回的是个Multiset,这个Multiset是以不重复的键对应的个数作为视图。这个Multiset可以通过支持移除操作而不是添加操作来修改Multimap。
5、values()视图能把Multimap里的所有值“平展”成一个Collection<V>。这个操作和Iterables.concat(multimap.asMap().values())很相似,只是它返回的是一个完整的Collection。
尽管Multimap的实现用到了Map,但Multimap<K, V>不是Map<K, Collection<V>>。因为两者有明显区别: 1.Multimap.get(key)一定返回一个非null的集合。但这不表示Multimap使用了内存来关联这些键,相反,返回的集合只是个允许添加元素的视图。 2.如果你喜欢像Map那样当不存在键的时候要返回null,而不是Multimap那样返回空集合的话,可以用asMap()返回的视图来得到Map<K, Collection<V>>。(这种情况下,你得把返回的Collection<V>强转型为List或Set)。 3.Multimap.containsKey(key)只有在这个键存在的时候才返回true。 4.Multimap.entries()返回的是Multimap所有的键值对。但是如果需要key-collection的键值对,那就得用asMap().entries()。 5.Multimap.size()返回的是entries的数量,而不是不重复键的数量。如果要得到不重复键的数目就得用Multimap.keySet().size()。
注:MultiMap是非线程安全的,转化为线程这全对象时可以参考:
private ListMultimap<Long,Long> map = ArrayListMultimap.create();
private Multimap<Long,Long> syncMap = Multimaps.synchronizedMultimap(map);


二、BidiMap
/****
* 所谓BidiMap,直译就是双向Map,可以通过key找到value,
* 也可以通过value找到key,这在我们日常的代码-名称匹配的时候很方便:
* 因为我们除了需要通过代码找到名称之外,往往也需要处理用户输入的名称,然后获取其代码。
* 需要注意的是BidiMap当中不光key不能重复,value也不可以。
*/
public static void demoBidiMap() {
System.out.println(StringUtils.center(" demoBidiMap ", 40, "="));
BidiMap bidiMap = new DualHashBidiMap();
bidiMap.put("BJ", "Beijing");
bidiMap.put("SH", "Shanghai");
bidiMap.put("GZ", "Guangzhou");
bidiMap.put("CD", "Chengdu");
System.out.println("Key-Value: BJ = " + bidiMap.get("BJ"));
System.out.println("Value-Key: Chengdu = " + bidiMap.getKey("Chengdu"));
System.out.println(StringUtils.repeat("=", 40));
}

三、LazyMap
/**所谓LazyMap,意思就是这个Map中的键/值对一开始并不存在,当被调用到时才创建.
* 我们这样来理解:我们需要一个Map,但是由于创建成员的方法很“重”(比如数据库访问),
* 或者我们只有在调用get()时才知道如何创建,或者Map中出现的可能性很多很多,
* 我们无法在get()之前添加所有可能出现的键/值对,
* 我们觉得没有必要去初始化一个Map而又希望它可以在必要时自动处理数据
*
*/
@SuppressWarnings(value = {"unchecked"})
public static void demoLazyMap()
{
System.out.println(StringUtils.center(" demoLazyMap ", 40, "="));
Factory factory = new Factory() {
public Object create() {
return new Date();
}
};
Map lazy = LazyMap.decorate(new HashMap(), factory);
System.out.println("map:"+lazy);//lazy为空
System.out.println(lazy.get("123"));
System.out.println(lazy.get("345"));
System.out.println(StringUtils.repeat("=", 40));
}
四、其它


其它链接请参见:http://ifeve.com/google-guava-newcollectiontypes/
MultiMap、BidiMap及LazyMap的使用的更多相关文章
- 一篇关于apache commons类库的详解
1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默默无闻的.在我看来,成功而默默无闻的那些框架值得我们格外的尊敬和关注,Jakarta C ...
- 一篇关于apache commons类库的详解[转]
1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默默无闻的.在我看来,成功而默默无闻的那些框架值得我们格外的尊敬和关注,Jakarta C ...
- commons工具类
转自:https://blog.csdn.net/leaderway/article/details/52387925 1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不 ...
- apache commons类库的学习
原文地址http://www.tuicool.com/articles/iyEbquE 1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默 ...
- C++ std::multimap
std::multimap template < class Key, // multimap::key_type class T, // multimap::mapped_type class ...
- Guava学习笔记:Guava新增集合类型-Multimap
在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业 ...
- [Google Guava]学习--新集合类型Multimap
每个有经验的Java程序员都在某处实现过Map<K, List<V>>或Map<K, Set<V>>,并且要忍受这个结构的笨拙. 假如目前有个需求是给两 ...
- 4.3 map和multimap
使用map multimap必须包含头文件map *:multimap 1)multimap定义 template<class Key,class Pred=less<Key>,cl ...
- STL中的map/multimap小结
(1)使用map/multimap之前必须包含头文件<map>:#include<map> 并且和所有的关联式容器一样,map/multimap通常以平衡二叉树来完成 (2)n ...
随机推荐
- Android程序的安全系统【转】
最近在移植Android过程中遇到了Android程序(apk)权限的问题.最近也对这方面进行了一些了解,在此和大家分享. Android框架是基于Linux内核构建,所以Android安全系统也是基 ...
- [iOS基础控件 - 6.12.2] Modal
A.概念 1.也可以用来切换控制器 2.如ActionSheet 除了push之外,还有另外一种控制器的切换方式,那就是Modal 任何控制器都能通过Modal的形式展示出来 Modal的默认效果 ...
- C#中的ref和out的区别
转载原地址 http://www.cnblogs.com/gjahead/archive/2008/02/28/1084871.html ref和out的区别在C# 中,既可以通过值也可以通过引用传递 ...
- js面形对象(2)
1.原型与in操作符 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用时,in操作符会在通过对象能够访问给定属性时,返回true,无论该属性是存在实例或者是存在于原型 ...
- Android之基于HTTP协议的下载
Android之基于HTTP协议的下载 http://www.blogjava.net/zh-weir/archive/2010/05/02/319892.html http://www.qianfa ...
- 工具栏停靠实现(toolbar docking)
// TODO: 如果不需要工具栏可停靠,则删除这三行 m_ToolBar_File.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_A ...
- jsp验证码点击刷新
<img src="<%=basePath%>manage/code" alt="验证码" height="20" ali ...
- iOS常用动画代码
使用前 需引入QuartzCore.framework, 并在相关文件中加入 #import "QuartzCore/QuartzCore.h" 定义 shakeFeedbackO ...
- Codeforces Gym 100002 B Bricks 枚举角度
Problem B Bricks" Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100002 ...
- Struts2之异常处理
一.学习案例:通过在input.jsp页面输入登录账号和password測试异常处理机制. 二.案例分析:struts2提供了局部异常处理机制和全局异常处理机制.局部优先于全局异常处理,当异常找不到局 ...