immutablecollections
public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");
class Foo {
Set<Bar> bars;
Foo(Set<Bar> bars) {
this.bars = ImmutableSet.copyOf(bars); // defensive copy!
}
}
不可变集合可以用如下多种方式创建:
- copyOf方法,如ImmutableSet.copyOf(set);
- of方法,如ImmutableSet.of(“a”, “b”, “c”)或 ImmutableMap.of(“a”, 1, “b”, 2);
- Builder工具,如:
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(new Color(0, 191, 255))
.build();
此外,对有序不可变集合来说,排序是在构造集合的时候完成的,如:
ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
会在构造时就把元素排序为a, b, c, d。
所有Guava不可变集合的实现都不接受null值。
asList视图
所有不可变集合都有一个asList()方法提供ImmutableList视图,来帮助你用列表形式方便地读取集合元素。例如,你可以使用 sortedSet.asList().get(k) 从ImmutableSortedSet中读取第k个最小元素。
asList()返回的ImmutableList通常是——并不总是——开销稳定的视图实现,而不是简单地把元素拷贝进List。也就是说,asList返回的列表视图通常比一般的列表平均性能更好,比如,在底层集合支持的情况下,它总是使用高效的contains方法。
Multiset
Guava提供了一个新集合类型 Multiset,它可以多次添加相等的元素。
可以用两种方式看待Multiset:
- 没有元素顺序限制的ArrayList。
- Map<E, Integer>,键为元素,值为计数。
Guava的Multiset API也结合考虑了这两种方式:
当把Multiset看成普通的Collection时,它表现得就像无序的ArrayList:
- add(E)添加单个给定元素
- iterator()返回一个迭代器,包含Multiset的所有元素(包括重复的元素)
- size()返回所有元素的总个数(包括重复的元素)
当把Multiset看作Map<E, Integer>时,它也提供了符合性能期望的查询操作:
- count(Object)返回给定元素的计数。HashMultiset.count的复杂度为O(1),TreeMultiset.count的复杂度为O(log n)。
- entrySet()返回Set<Multiset.Entry>,和Map的entrySet类似。
- elementSet()返回所有不重复元素的Set,和Map的keySet()类似。
- 所有Multiset实现的内存消耗随着不重复元素的个数线性增长。
public static void main(String[] args) {
String str = "this a cat and that is a mice where is the food";
//分割字符串
String[] strs = str.split(" ");
//把字符串放进Multiset里面
Multiset<String> set= HashMultiset.create();
for(String temp:strs){
set.add(temp);
}
//获取Multiset里的元素
Set<String> eset=set.elementSet();
for(String temp:eset){
System.out.println(temp+"---------->"+set.count(temp));//count记录出现的次数
}
}
Multiset不是Map
请注意,Multiset不是Map<E, Integer>,虽然Map可能是某些Multiset实现的一部分。准确来说Multiset是一种Collection类型,并履行了Collection接口相关的契约。关于Multiset和Map的显著区别还包括:
- Multiset中的元素计数只能是正数。任何元素的计数都不能为负,也不能是0。elementSet()和entrySet()视图中也不会有这样的元素。
- multiset.size()返回集合的大小,等同于所有元素计数的总和。对于不重复元素的个数,应使用elementSet().size()方法。(因此,add(E)把multiset.size()增加1)
- multiset.iterator()会迭代重复元素,因此迭代长度等于multiset.size()。
Multiset支持直接增加、减少或设置元素的计数。setCount(elem, 0)等同于移除所有elem。 - 对multiset 中没有的元素,multiset.count(elem)始终返回0。
Multimap
Multimap是把键映射到任意多个值的一般方式。Multimap是键可以重复的map
这里的意思,内部实现就是当键重复时,他的值不会覆盖,而是存到对应于键的一个容器里。这样子我们可以用他来统计重复的具体内容。
以下使用Multimap统计老师教授的课程:
public static void main(String[] args) {
//统计每个老师教的课程
Map<String, String> map=new HashMap<>();
map.put("电力电子技术","王伟");
map.put("单片机","王伟");
map.put("微机", "刘一帆");
map.put("局域网", "刘一帆");
map.put("高数", "李小伟");
map.put("现控", "沈浩");
Multimap<String, String> teachers=ArrayListMultimap.create();
//迭代之前的map,吧元素存进新的Multimap,但是用老师来当做键,这样子每个老师的课程就存在一起了
Iterator<Map.Entry<String, String>> it=map.entrySet().iterator();
while(it.hasNext()){
Entry<String, String> entry=it.next();
String key=entry.getKey();
String value=entry.getValue();
teachers.put(value,key);
}
//获的键
Set<String> keys=teachers.keySet();
for(String key:keys){
Collection<String> col=teachers.get(key);
System.out.println(key+"---->"+col);
}
}
BiMap
键跟值都不能重复的map。因为键-值都不能重复,所以可以反转inverse();此时键值对调,就可以通过值来找键了。
public static void main(String[] args) {
BiMap<String, String> map=HashBiMap.create();
map.put("Viking", "viking@qq.com");
map.put("good", "good@qq.com");
//因为键-值都不能重复,所以可以反转inverse();反转,此时键值对调,就可以通过值来找键了
String usr=map.inverse().get("viking@qq.com");
System.out.println(usr);
}
Table
Table是Guava提供的一个接口 Interface Table<R,C,V>,由rowKey+columnKey+value组成 它有两个键,一个值,和一个n行三列的数据表类似,n行取决于Table对对象中存储了多少个数据。
主要使用的方法有:
- 所有行数据:cellSet()
- 所有第一个key值:rowKeySet()
- 所有课程:columnKeySet()
- 所有成绩:values()
- 课程成绩表:rowMap()+get(stu)/row(stu)
- 学生成绩表 columnMap()+get(course)/column(course)
给出一个学生-课程-成绩表,测试上面提到的方法,表如下 :
把数据存储到Table中,通过HashBasedTable.create()新建一个Table对象。
Table<String,String,Integer> tables=HashBasedTable.create();
tables.put("a", "javase", 80);
tables.put("b", "javaee", 90);
tables.put("c", "javame", 100);
tables.put("d", "guava", 70);
得到所有行数据 tables.cellSet()
Set<Cell<String,String,Integer>> cells=tables.cellSet();
for(Cell<String,String,Integer> temp:cells){
System.out.println(temp.getRowKey()+" "+temp.getColumnKey()+" "+temp.getValue());
}
输出结果:
d guava 70
b javaee 90
c javame 100
a javase 80
得到所有学生 rowKeySet()
Set<String> students=tables.rowKeySet();
for(String str:students){
System.out.print(str+"\t");
}
输出结果:
d b c a
得到所有课程 columnKeySet()
Set<String> courses=tables.columnKeySet();
for(String str:courses){
System.out.print(str+"\t");
}
输出结果:
guava javaee javame javase
得到所有成绩:values
Collection<Integer> scores=tables.values();
for(Integer in:scores){
System.out.print(in+"\t");
}
输出结果:
70 90 100 80
得到学生的课程成绩表 rowMap+get(stu)/row(stu)
for(String str:students){
Map<String,Integer> rowMap=tables.row(str);
Set<Entry<String,Integer>> setEntry=rowMap.entrySet();
for(Entry<String,Integer> entry:setEntry){
System.out.println(entry.getKey()+" "+entry.getValue());
}
}
输出结果:
guava 70
javaee 90
javame 100
javase 80
得到学生的姓名成绩表 columnMap+get(course)/column(course)
for (String str : courses) {
Map<String, Integer> rowMap2 = tables.column(str);
Set<Entry<String, Integer>> setEntry2 = rowMap2.entrySet();
for (Entry<String, Integer> entry : setEntry2) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
输出结果为:
d 70
b 90
c 100
a 80
ClassToInstanceMap
ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象。
为了扩展Map接口,ClassToInstanceMap额外声明了两个方法:T getInstance(Class) 和T putInstance(Class, T),从而避免强制类型转换,同时保证了类型安全。
ClassToInstanceMap有唯一的泛型参数,通常称为B,代表Map支持的所有类型的上界。例如:
ClassToInstanceMap<Number> numberDefaults=MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));
从技术上讲,ClassToInstanceMap实现了Map<Class<? extends B>, B>——或者换句话说,是一个映射B的子类型到对应实例的Map。这让ClassToInstanceMap包含的泛型声明有点令人困惑,但请记住B始终是Map所支持类型的上界——通常B就是Object。
工具类
Guava提供了能够推断范型的静态工厂方法:
List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();
Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();
把List按指定大小分割和反转。
List countUp = Ints.asList(1, 2, 3, 4, 5);
List countDown = Lists.reverse(theList); // {5, 4, 3, 2, 1}
List<List> parts = Lists.partition(countUp, 2);//{{1,2}, {3,4}, {5}}
这里只记录了使用过的方法。
具体查看:[Google Guava] 2.3-强大的集合工具类:java.util.Collections中未包含的集合工具