总结:
1. Multimap允许key重复(Map是不允许的,若在装入Map时,出现相同key,后者会将前者覆盖)。
2. 判断两个集合是否存在交集:!Collections.disjoint(list1, list2);
或!CollectionUtils.containsAny(list1,list2);
3. 求集合的包含和所属关系:b.containsAll(a)或CollectionUtils.containsAll(b, a)
4. key value都相同[键值对相同,相同的key,相同的value],使用HashMultimap会只
保留一份记录,因为它是继承自AbstractSetMultimap这样的Set类实现的,可以使用
ArrayListMultimap等继承自AbstractListMultimap的类来实例化对象。
前不久在这篇 使用 Google Guava 美化你的 Java 代码:1~4 中的 “一个集合统治一切 – Multimap” 部分提到过这货,不过当时那篇文章受限于篇幅,例子举的不够详尽,估计很多同学看了还是云里雾里,一头雾水。
说个具体的应用场景吧:
比如现在我有一份日志记录,每条记录的内容是一个 url 对应一个访客的 userid,我现在想得到 每个 url 对应的 pv、uv 数据,你会怎么做?
普通青年一般这么想的:用 url 做 key,userid 作为对应 list 的内容:
1
|
Map
new
HashMap
|
然后你需要检查key是否存在,否则创建一个,最后代码成为这个样子:
1
2
3
4
5
6
7
8
|
void
putMyObject(String key, Object value) {
List
if
(myClassList ==
null
) {
myClassList =
new
ArrayList
myClassListMap.put(key,myClassList);
}
myClassList.add(value);
}
|
如果你希望检查List中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么需要更多的代码。
看到这里不禁感叹一句:这特么都什么玩意啊。。。
恩,懒人总有懒人的办法,习惯脚本语言的我,很难忍受 java 的这种臃肿的代码了,下面看看用之前提到的 Guava MultiMap 怎么优雅的解决这个问题。
1
|
Multimap
|
这里需要注意,所有的guava的集合都有create()方法,这个好处就是比较简单,你不用重复泛型信息了。
好了,开始使用Multimap了:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package
com.test;
import
java.util.Collection;
import
com.google.common.collect.ArrayListMultimap;
import
com.google.common.collect.ImmutableSet;
import
com.google.common.collect.Multimap;
public
class
MutliMapTest {
public
static
void
main(String... args) {
Multimap
// Adding some key/value
myMultimap.put(
"Fruits"
,
"Bannana"
);
myMultimap.put(
"Fruits"
,
"Apple"
);
myMultimap.put(
"Fruits"
,
"Pear"
);
myMultimap.put(
"Fruits"
,
"Pear"
);
myMultimap.put(
"Vegetables"
,
"Carrot"
);
// Getting the size
int
size = myMultimap.size();
System.out.println(size);
// 5
// Getting values
Collection
"Fruits"
);
System.out.println(fruits);
// [Bannana, Apple, Pear, Pear]
System.out.println(ImmutableSet.copyOf(fruits));
// [Bannana, Apple, Pear] 这里有个去重的做法
// Set
// Set
Collection
"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, Apple, Pear]
// Remove all values for a key
myMultimap.removeAll(
"Fruits"
);
System.out.println(myMultimap.get(
"Fruits"
));
// [] (Empty Collection!)
}
}
|
这里有一点你可能会疑惑,就是为何get方法返回的是一个collection而不是list,这是因为前者会更加有用。如果你需要基于multimap直接操作list或者set,那么可以使用在定义类型的时候使用子类名称:ListMultimap,SetMultimap和SortedSetMultimap。例如:
1
2
3
|
ListMutlimap
List
"myKey"
);
// Returns a List, not a Collection.
|
好了,基本就是这样,你可以参考API获取更多信息:
http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/index.html
PS: 下面再补充另一个问题:如何判断两个集合是否存在交集?
(1)普通写法:双层 for 循环遍历两个集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
boolean
found =
false
;
for
(Object1 object1 : list1){
for
(Object2 object2: list2){
if
(object1.getAttributeSame() == object2.getAttributeSame()){
found =
true
;
break
;
//also do something
}
}
if
(!found){
//do something
}
found =
false
;
}
|
(2)JDK 自带的集合方法:disjoint
1
|
!Collections.disjoint(list1, list2);
|
(3) 使用第三方库: Apache Commons CollectionUtils
http://commons.apache.org/proper/commons-collections/javadocs/api-release/index.html
1
2
3
4
5
6
7
|
if
(CollectionUtils.containsAny(list1,list2)
{
//do whatever
}
else
{
//do other thing
}
|
(4)不太高效的,但是简洁可用的变通方法:retainAll
1
2
|
if
(!
new
HashSet
// at least one element is shared
|
(5)顺便说下如何求集合的包含、所属关系:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public
class
Test {
public
static
void
main(String[] args)
throws
IOException {
Set a =
new
HashSet() {
{
add(
1
);
add(
2
);
}
};
Set b =
new
HashSet() {
{
add(
2
);
add(
3
);
add(
1
);
}
};
System.out.println(b.containsAll(a));
System.out.println(CollectionUtils.containsAll(b, a));
}
}
|
来源: <http://my.oschina.net/leejun2005/blog/179645>