004-guava 集合-新增集合类型-MultiSet, MultiMap, BiMap , Table, ClassToInstanceMap, RangeSe, RangeMap等
一、概述
Guava引入了很多JDK没有的、但明显有用的新集合类型。这些新类型是为了和JDK集合框架共存,而没有往JDK集合抽象中硬塞其他概念。作为一般规则,Guava集合非常精准地遵循了JDK接口契约。
二、使用
2.1、MultiSet[无序+可重复]-工具类Multisets
Guava提供了一个新集合类型 Multiset,它可以多次添加相等的元素。维基百科从数学角度这样定义Multiset:”集合[set]概念的延伸,它的元素可以重复出现…与集合[set]相同而与元组[tuple]相反的是,Multiset元素的顺序是无关紧要的:Multiset {a, a, b}和{a, b, a}是相等的”。——译者注:这里所说的集合[set]是数学上的概念,Multiset继承自JDK中的Collection接口,而不是Set接口,所以包含重复元素并没有违反原有的接口契约。
这个接口没有实现java.util.Set接口,Set接口规定里面是不能够放入重复的元素,如果放入重复元素会被覆盖掉的;然而Multiset接口却是可以放入重复元素的,Set接口中的元素是[1,2,3],Multiset中确可以[1✖️2,2✖️3,3✖️3]来表示多个相同的元素。
Guava提供了多种Multiset的实现,大致对应JDK中Map的各种实现:
| Map | 对应的Multiset | 是否支持null元素 |
| HashMap | HashMultiset | 是 |
| TreeMap | TreeMultiset | 是(如果comparator支持的话) |
| LinkedHashMap | LinkedHashMultiset | 是 |
| ConcurrentHashMap | ConcurrentHashMultiset | 否 |
| ImmutableMap | ImmutableMultiset | 否 |
使用
@Test
public void testMultiSet(){
Multiset<String> multiset= HashMultiset.create();
multiset.add("aa");
multiset.add("bb");
multiset.add("cc",2);
System.out.println(multiset);//[aa, bb, cc x 2]
System.out.println(multiset.size()); //
System.out.println(multiset.count("cc"));//
multiset.setCount("bb",4);
System.out.println(multiset);//[aa, bb x 4, cc x 2]
}
2.2、SortedMultiset
SortedMultiset是Multiset 接口的变种,它支持高效地获取指定范围的子集。比方说,你可以用 latencies.subMultiset(0,BoundType.CLOSED, 100, BoundType.OPEN).size()来统计你的站点中延迟在100毫秒以内的访问,然后把这个值和latencies.size()相比,以获取这个延迟水平在总体访问中的比例。
TreeMultiset实现SortedMultiset接口。在撰写本文档时,ImmutableSortedMultiset还在测试和GWT的兼容性。
2.3、MultiMap[key-value key可以重复 ]-工具类Multimaps
程序开发中使用Map<K, List<V>>或Map<K, Set<V>>,并且要忍受这个结构的笨拙。例如,Map<K, Set<V>>通常用来表示非标定有向图。Guava的 Multimap可以很容易地把一个键映射到多个值。换句话说,Multimap是把键映射到任意多个值的一般方式。
很少会直接使用Multimap接口,更多时候你会用ListMultimap或SetMultimap接口,它们分别把键映射到List或Set。
Multimap提供了多种形式的实现。在大多数要使用Map<K, Collection<V>>的地方,你都可以使用它们:
| 实现 | 键行为类似 | 值行为类似 |
| ArrayListMultimap | HashMap | ArrayList |
| HashMultimap | HashMap | HashSet |
| LinkedListMultimap* | LinkedHashMap* | LinkedList* |
| LinkedHashMultimap** | LinkedHashMap | LinkedHashMap |
| TreeMultimap | TreeMap | TreeSet |
| ImmutableListMultimap | ImmutableMap | ImmutableList |
| ImmutableSetMultimap | ImmutableMap | ImmutableSet |
除了两个不可变形式的实现,其他所有实现都支持null键和null值
*LinkedListMultimap.entries()保留了所有键和值的迭代顺序。详情见doc链接。
**LinkedHashMultimap保留了映射项的插入顺序,包括键插入的顺序,以及键映射的所有值的插入顺序。
请注意,并非所有的Multimap都和上面列出的一样,使用Map<K, Collection<V>>来实现(特别是,一些Multimap实现用了自定义的hashTable,以最小化开销)
如果你想要更大的定制化,请用Multimaps.newMultimap(Map, Supplier<Collection>)或list和 set版本,使用自定义的Collection、List或Set实现Multimap。
示例:
@Test
public void testMultiMap() {
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("fruit", "bannana");
multimap.put("fruit", "apple");//key可以重复
multimap.put("fruit", "apple");//value可以重复,不会覆盖之前的
multimap.put("fruit", "peach");
multimap.put("fish", "crucian");//欧洲鲫鱼
multimap.put("fish", "carp");//鲤鱼
Collection<String> fruits = multimap.get("fruit");
System.err.println(fruits);//[bannana, apple, apple, peach] //对比 HashMultimap
Multimap<String,String> multimap2= HashMultimap.create();
multimap2.put("fruit2", "bannana");
multimap2.put("fruit2", "apple");
multimap2.put("fruit2", "apple"); System.err.println(multimap2.size());//
System.err.println(multimap2.get("fruit2"));//[apple, bannana] 注意: 这里只有一个apple
}
2.4、BiMap[双向Map(Bidirectional Map) 键与值都不能重复]
传统上,实现键值对的双向映射需要维护两个单独的map,并保持它们间的同步。但这种方式很容易出错,而且对于值已经在map中的情况,会变得非常混乱。例如:
Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();
nameToId.put("Bob", 42);
idToName.put(42, "Bob");
//如果"Bob"和42已经在map中了,会发生什么?
//如果我们忘了同步两个map,会有诡异的bug发生...
BiMap<K, V>是特殊的Map:
可以用 inverse()反转BiMap<K, V>的键值映射
保证值是唯一的,因此 values()返回Set而不是普通的Collection
在BiMap中,如果你想把键映射到已经存在的值,会抛出IllegalArgumentException异常。如果对特定值,你想要强制替换它的键,请使用 BiMap.forcePut(key, value)。
@Test
public void testBiMap() {
BiMap<String, Integer> userId = HashBiMap.create();
userId.put("lhx",30);
userId.put("zll",28);
String userForId = userId.inverse().get(30);
System.out.println(userForId);//lhx userId.put("jm",30);//报错
String userForId2 = userId.inverse().get(30);
System.out.println(userForId2);//lhx
}
BiMap的各种实现
| 键–值实现 | 值–键实现 | 对应的BiMap实现 |
| HashMap | HashMap | HashBiMap |
| ImmutableMap | ImmutableMap | ImmutableBiMap |
| EnumMap | EnumMap | EnumBiMap |
| EnumMap | HashMap | EnumHashBiMap |
注:Maps类中还有一些诸如synchronizedBiMap的BiMap工具方法.
2.5、Table【双键的Map Map--> Table-->rowKey+columnKey+value //和sql中的联合主键有点像】-工具类Tables
行、列、值。当使用多个键做索引的时候,可能会用类似Map<FirstName, Map<LastName, Person>>的实现,这种方式很丑陋,使用上也不友好。
Guava为此提供了新集合类型Table,它有两个支持所有类型的键:”行”和”列”。
Table有如下几种实现:
- HashBasedTable:本质上用HashMap<R, HashMap<C, V>>实现;
- TreeBasedTable:本质上用TreeMap<R, TreeMap<C,V>>实现;
- ImmutableTable:本质上用ImmutableMap<R, ImmutableMap<C, V>>实现;注:ImmutableTable对稀疏或密集的数据集都有优化。
- ArrayTable:要求在构造时就指定行和列的大小,本质上由一个二维数组实现,以提升访问速度和密集Table的内存利用率。ArrayTable与其他Table的工作原理有点不同,请参见Javadoc了解详情。
示例
@Test
public void testTable() {
Table<String, String, Integer> table = HashBasedTable.create();
table.put("a", "b", 4);
table.put("a", "c", 20);
table.put("b", "c", 5); Map<String, Integer> a = table.row("a");// returns a Map mapping {b=4, c=20}
System.out.println(a); Map<String, Integer> column = table.column("c");// returns a Map mapping {a=20, b=5}
System.out.println(column); Integer integer = table.get("a", "c");
System.out.println(integer); //
}
2.6、ClassToInstanceMap
ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象。
为了扩展Map接口,ClassToInstanceMap额外声明了两个方法:T getInstance(Class<T>) 和T putInstance(Class<T>, T),从而避免强制类型转换,同时保证了类型安全。
ClassToInstanceMap有唯一的泛型参数,通常称为B,代表Map支持的所有类型的上界。例如:
class Person{
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
@Test
public void testClassToInstanceMap() {
ClassToInstanceMap<Person> instanceMap=MutableClassToInstanceMap.create();
instanceMap.putInstance(Person.class, new Person("lhx"));
instanceMap.putInstance(Person.class, new Person("lhx2"));
Person person = instanceMap.get(Person.class); // Person{name='lhx2'} 存储了 后一个
System.out.println(person);
}
从技术上讲,ClassToInstanceMap<B>实现了Map<Class<? extends B>, B>——或者换句话说,是一个映射B的子类型到对应实例的Map。这让ClassToInstanceMap包含的泛型声明有点令人困惑,但请记住B始终是Map所支持类型的上界——通常B就是Object。
对于ClassToInstanceMap,Guava提供了两种有用的实现:MutableClassToInstanceMap和 ImmutableClassToInstanceMap。
2.7、RangeSet
描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。例如:
@Test
public void testRangeSet() {
RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 10)); // {[1,10]}
rangeSet.add(Range.closedOpen(11, 15));//不相连区间:{[1,10], [11,15)}
rangeSet.add(Range.closedOpen(15, 20)); //相连区间; {[1,10], [11,20)}
rangeSet.add(Range.openClosed(0, 0)); //空区间; {[1,10], [11,20)}
rangeSet.remove(Range.open(5, 10)); //分割[1, 10]; {[1,5], [10,10], [11,20)} System.out.println(rangeSet);//[[1..5], [10..10], [11..20)]
}
请注意,要合并Range.closed(1, 10)和Range.closedOpen(11, 15)这样的区间,你需要首先用Range.canonical(DiscreteDomain)对区间进行预处理,例如DiscreteDomain.integers()。
注:RangeSet不支持GWT,也不支持JDK5和更早版本;因为,RangeSet需要充分利用JDK6中NavigableMap的特性。
2.8、RangeMap
RangeMap描述了”不相交的、非空的区间”到特定值的映射。和RangeSet不同,RangeMap不会合并相邻的映射,即便相邻的区间映射到相同的值。例如:
@Test
public void testRangeMap() {
RangeMap<Integer, String> rangeMap = TreeRangeMap.create(); rangeMap.put(Range.closed(1, 10), "foo"); //{[1,10] => "foo"}
rangeMap.put(Range.open(3, 6), "bar"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo"}
rangeMap.put(Range.open(10, 20), "foo"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo", (10,20) => "foo"}
rangeMap.remove(Range.closed(5, 11)); //{[1,3] => "foo", (3,5) => "bar", (11,20) => "foo"} System.out.println(rangeMap);//[[1..3]=foo, (3..5)=bar, (11..20)=foo]
}
方式
004-guava 集合-新增集合类型-MultiSet, MultiMap, BiMap , Table, ClassToInstanceMap, RangeSe, RangeMap等的更多相关文章
- 强大的Guava中的新集合类型: Multiset, Multimap, BiMap, Table, ClassToInstanceMap, RangeSet, RangeMap等
一 Multiset /** * 新类型集合: Multiset: Multiset就是可以保存多个相同的对象,并且无序 * 占据了List和Set之间的一个灰色地带 * 其他实现: TreeMult ...
- Guava新增集合类型-Multimap
Guava新增集合类型-Multimap 在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比 ...
- Guava新增集合类型-Multiset
Guava新增集合类型-Multiset Guava引进了JDK里没有的,但是非常有用的一些新的集合类型.所有这些新集合类型都能和JDK里的集合平滑集成.Guava集合非常精准地实现了JDK定义的接口 ...
- Guava学习笔记:Guava新增集合类型-Multimap
在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业 ...
- [Google Guava]学习--新集合类型Multimap
每个有经验的Java程序员都在某处实现过Map<K, List<V>>或Map<K, Set<V>>,并且要忍受这个结构的笨拙. 假如目前有个需求是给两 ...
- [Google Guava]学习--新集合类型Multiset
Guava提供了一个新集合类型Multiset,它可以多次添加相等的元素,且和元素顺序无关.Multiset继承于JDK的Cllection接口,而不是Set接口. Multiset主要方法介绍: a ...
- Guava新增集合类型-Bimap
Guava新增集合类型-Bimap BiMap提供了一种新的集合类型,它提供了key和value的双向关联的数据结构. 通常情况下,我们在使用Java的Map时,往往是通过key来查找value的,但 ...
- [Google Guava] 2.2-新集合类型
转自:并发编程网 原文链接:http://ifeve.com/google-guava-newcollectiontypes/ 链接博客其他文章中还有更多的guava其他功能的描述,有空可慢慢看. G ...
- Guava集合--新集合类型
Guava引入了很多JDK没有的.但我们发现明显有用的新集合类型.这些新类型是为了和JDK集合框架共存,而没有往JDK集合抽象中硬塞其他概念.作为一般规则,Guava集合非常精准地遵循了JDK接口契约 ...
随机推荐
- 实用mysql数据库命令
连接:mysql -h主机地址 -u用户名 -p用户密码 (注:u与root可以不用加空格,其它也一样)断开:exit (回车) 创建授权:grant select on 数据库.* to 用户名@登 ...
- ORA-12638: Credential retrieval failed 解决办法
ORA-12638 ORA-12638: Credential retrieval failed 身份证明检索失败 解决办法: 修改sqlnet.ora文件(位置:$ORACLE_HOME ...
- Redis-3.2.1集群内网部署
摘要: Redis-3.2.1集群内网部署 http://rubygems.org国内连不上时的一种Redis集群部署解决方案.不足之处,请广大网友指正,谢谢! 一. 关于redis cluster ...
- z-tree的使用bug
最近折腾了下z-tree,这个存在一个bug: 新增icon出不来,废话少说上代码: <style type="text/css"> .ztree li span.bu ...
- 语法速学,返回数组 repeated修饰符
重新编写proto文件 syntax = "proto3"; package services; import "google/api/annotations.proto ...
- SSM整合Dubbo案例
一.Consumer子类 MyController类 @Controller @RequestMapping("/login") public class MyController ...
- C# mysql 处理 事务 回滚 提交
MySqlConnection myCon; void iniMysql() { //连接数据库 myCon = new MySqlConnection("server=127.0.0.1; ...
- js使用WebUploader做大文件的分块和断点续传
1 背景 用户本地有一份txt或者csv文件,无论是从业务数据库导出.还是其他途径获取,当需要使用蚂蚁的大数据分析工具进行数据加工.挖掘和共创应用的时候,首先要将本地文件上传至ODPS,普通的小文件通 ...
- admin站点管理
admin中的显示 class Saltstack_GroupAdmin(admin.ModelAdmin): list_display = ['group_name','salt_minion_id ...
- shell脚本之字符串运算的使用
字符串运算符 下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg": 运算符 说明 举例 = 检测两个字符串是否相等,相等返回 ...