Guava学习(二)-集合

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", "[email protected]");
        map.put("good", "[email protected]");
        //因为键-值都不能重复,所以可以反转inverse();反转,此时键值对调,就可以通过值来找键了
        String usr=map.inverse().get("[email protected]");
        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中未包含的集合工具

发布了44 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/hxyascx/article/details/99447965