Guava对jdk的集合进行了扩展。这也是Guava最常用的地方。
- Guava不可变集合
- 提供了一些新的集合
- 提供了比jdk更加强大的工具类
- 提供了扩展工具类
不可变集合,说起不可变集合,其实也就是不可变对象。所谓不可变对象,是指一个对象被创建后,它的状态就不能再改变了。其最大的特点就是具有很高的安全性。而不可变集合的优点主要有以下方面:
- 当对象被不可信的库调用时,不可变形式是安全的;
- 不可变对象被多个线程调用时,不存在竞态条件问题;
- 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
- 不可变对象因为有固定不变,可以作为常量来安全使用;
Guava提供了比jdk更加优秀的不可变集合,每种不可变集合都有3种创建方式,而且Guava也给每一种不可变集合提供了视图。我们在这里就用不可变的List来展示一下。
注:Guava的不可变集合是不支持null的。即Guava的不可变集合中是不能存储null。
ArrayList list=new ArrayList();
list.add("zhaotong1");
list.add("zhaotong2");
list.add("zhaotong3");
System.out.println(list);
//第一种创建方式
ImmutableList list1=ImmutableList.copyOf(list);
//第二种创建方式
ImmutableList list2=ImmutableList.of("zhaotong","zhaotong1");
System.out.println(list2);
//第三种创建方式
ImmutableList list3=ImmutableList.builder().add("ab").add("cd")
.add("as","c","das").build();
System.out.println(list3);
//提供的视图
ImmutableList list4=list3.asList();
System.out.println(list4.get(4));
这就是Guava中为我们提供的不可变List,当然还有不可变Set,Map等。如果要创建 的是一个不可变的排序集合,那么创建时,会自动为其排序,即该集合在构造时就是有序的。而Guava为每个集合所提供的视图,比原有集合在效率等方面更加强大。
接下来我们看看Guava为我们提供的新的集合类型。
Multiset接口:它可以多次的添加元素,他是继承与jdk中Collection接口而不是Set接口,所以可以包含重复元素但并没有违反原有契约。这里我们就以HashMultiset来加以说明其用法。其实Muiltiset我们可以把他当做集合来看,也可当做map来看。从map角度看其键为实体,而值为实体的数量。
下面就是HashMultiset的一些初级使用。
HashMultiset hset=HashMultiset.create();
//添加元素 ,可以添加重复元素
hset.add("zhaotong");
hset.add("zhaotong");
hset.add("zhaotong1");
//返回一个迭代器
Iterator itor=hset.iterator();
//把其看作把Multiset看作Map时 E 代表实体类型,而值就是该元素的数量
Set> set=hset.entrySet();
//
System.out.println(hset.count("zhaotong"));
Multimap接口:我们可以利用guava提供的此接口,方便的将一个键映射到多个值。代码是最好的文档,下面我们就用ArrayListMultimap做一个简单的使用。
//Multimap接口 很容易把一个键映射到多个值
ArrayListMultimap asm=ArrayListMultimap.create();
List arr=Arrays.asList(1,2,3,4,5,6);
// putAll(String key,Iterable extends V> values)
asm.putAll("zhaotong", arr);
asm.put("zhaoritian", 9999);
asm.forEach(new BiConsumer() {
@Override
public void accept(String t, Integer u) {
System.out.println(t+" "+u);
}
});
System.out.println(asm.get("zhaotong"));
此外,Multimap 接口还给我们提供了视图。
Map> map=asm.asMap();
其运行结果如下:
这里只是最简单的介绍一下此接口,如果想看更深层次的,请关注我的。
BiMap接口:其实BiMap接口主要是实现键值对的双向映射。这里我们需要保持键值都不能重复,我们这里用HashBiMap做个示例:
BiMap bi=HashBiMap.create();
bi.put("zhaotong", 1);
String s=bi.inverse().get(1);
System.out.println(s);
运行结果:
这里的inverse()方法反转BiMap
Set set=bi.values();
Table接口:你想使用多个键做索引的时候,你可能会用类似Map
下面我们就是使用其实现类HashBasedTable来进行演示。
//创建一个Table,其实键可以看成一个二维数组。第一个键为行,第二个为列
Table table11=HashBasedTable.create();
//往table中存入键值对
table11.put("zt", "xyy", 1);
table11.put("zt", "xyy1", 1);
table11.put("zt1", "xyy1", 1);
table11.put("zt2", "xyy1", 1);
//以行为基础转化为map
Map> map=table11.rowMap();
System.out.println(map);
//得到行所对应键的Set集合
Set set=table11.rowKeySet();
System.out.println(set);
//得到列所对应键的Set集合
Set s=table11.columnKeySet();
System.out.println(s);
//得到指定行所对应的键值对。
Map map1=table11.row("zt");
System.out.println(map1);
//以列为基础得到map
Map> map3=table11.columnMap();
System.out.println(map3);
//得到指定列所对应的键值对
Map map4=table11.column("xyy1");
System.out.println(map4);
以上代码运行结果:
ClassToInstanceMap:它的键是类型,而值是符合键所指类型的对象。
为了扩展Map接口,ClassToInstanceMap额外声明了两个方法:[T getInstance(Class
示例如下:
//创建一个对象
ClassToInstanceMap cls=MutableClassToInstanceMap.create();
//放入指定类型的实例
cls.putInstance(Integer.class, Integer.valueOf(1));
//取出指定类型的实例
System.out.println(cls.getInstance(Integer.class));
RangeSet:RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。
示例代码如下:
//数字区间
RangeSet rs=TreeRangeSet.create();
rs.add(Range.closed(0, 10));
rs.add(Range.closed(11, 15));
rs.add(Range.closed(1, 16));
rs.add(Range.closedOpen(15, 20));
System.out.println(rs);
//字母区间
RangeSet rs1=TreeRangeSet.create();
rs1.add(Range.closed("a", "d"));
rs1.add(Range.closed("h", "y"));
rs1.add(Range.closed("aa", "ac"));
System.out.println(rs1);
//视图,RangeSet提供了非常强大的视图
//返回RangeSet的补集视图
RangeSet rsc=rs.complement();
System.out.println(rsc);// 输出结果:[(-∞..0), [20..+∞)]
//返回RangeSet的交集集合
RangeSet rsubr=rs.subRangeSet(Range.closed(15, 50));
System.out.println(rsubr);//输出结果:[[15..20)]
//Set>表现RangeSet,这样可以遍历其中的Range
rs.add(Range.closed(30, 50));
Set> rsset=rs.asRanges();
System.out.println(rs.asRanges()); //输出结果:[[0..20), [30..50]]
//RangeSet 有很多查询方法,包括:contains(C)//是否包含给定元素,rangeContaining(C)//是否包含给定元素的区间,encloses(Range)://是否有包含给定区间的区间
//返回包括所有区间的最小区间
Range ri= rs.span();
System.out.println(ri);//输出结果: [0..50]
- RangeMap:”不相交的、非空的区间”到特定值的映射.
示例代码如下:
RangeMap rm=TreeRangeMap.create();
//区间作为键不能相同
rm.put(Range.closed(10, 19), "zhaotong");
rm.put(Range.open(10, 19),"zhaotong1");
rm.put(Range.closed(19,34),"zhaotong2");
System.out.println(rm);//输出结果:[[10..10]=zhaotong, (10..19)=zhaotong1, [19..34]=zhaotong2]
//提供的视图
Map,String> map=rm.asMapOfRanges();
System.out.println(map);//输出结果:{[10..10]=zhaotong, (10..19)=zhaotong1, [19..34]=zhaotong2}
//返回与指定区间的交集
RangeMap rms= rm.subRangeMap(Range.closed(10, 10));
System.out.println(rms);//输出结果:{[10..10]=zhaotong}