Google Guava 快速入门 —— 【新集合】Multiset 类

Google Guava 快速入门.jpg

Multiset —— 把重复的元素放入集合

一、接口声明

以下是 com.google.common.collect.Multiset<E> 接口的声明:

@GwtCompatible
public interface Multiset<E> extends Collection<E>

二、接口方法

官方文档:https://google.github.io/guava/releases/27.0.1-jre/api/docs/com/google/common/collect/Multiset.html

修饰符和类型方法描述
booleanadd(E element) 
向其中添加单个元素.
intadd(E element, int occurrences) 
增加给定元素在Multiset中的计数
booleancontains(@Nullable Object element) 
是否包含元素.
booleancontainsAll(Collection<?> elements) 
如果这个多集至少包含一个出现的指定集合中的所有元素.
intcount(@Nullable Object element) 
返回给定参数元素的个数.
Set<E>elementSet() 
Multiset中不重复元素的集合,类型为Set
Set<Multiset.Entry<E>>entrySet() 
和Map的entrySet类似,返回Set<multiset.entry>,其中包含的Entry支持getElement()和getCount()方法
booleanequals(@Nullable Object object) 
比较指定对象与此multiset是否相等.
default voidforEach(Consumer<? super E> action) 
元素遍历.
default voidforEachEntry(ObjIntConsumer<? super E> action) 
为此多集中的每个不同元素运行指定的操作,以及该元素的出现次数。
inthashCode() 
返回此multiset的哈希码.
Iterator<E>iterator() 
返回一个迭代器,包含Multiset的所有元素(包括重复的元素)
booleanremove(@Nullable Object element) 
移除一个元素,其count值 会响应减少.
intremove(@Nullable Object element, int occurrences) 
减少给定元素在Multiset中的计数
booleanremoveAll(Collection<?> c) 
去除出现给给定集合参数的所有的元素.
booleanretainAll(Collection<?> c) 
保留出现在给定集合参数的所有的元素.
intsetCount(E element, int count) 
设置给定元素在Multiset中的计数,不可以为负数.
booleansetCount(E element, int oldCount, int newCount) 
将符合原有重复个数的元素修改为新的重复次数.
intsize() 
返回所有元素的总个数(包括重复的元素)
default Spliterator<E>spliterator() 
在此集合中的元素上创建Spliterator.
StringtoString() 
返回该对象的字符串表示.

从接口 java.util.Collection 继承的方法有:addAllclearisEmptyparallelStreamremoveIfstreamtoArray

三、Multiset 介绍

在JDK中,List 和 Set 有一个基本的区别,就是 List 可以包含多个相同对象,且是有顺序的,而 Set 不能有重复,且不保证顺序(有些实现有顺序,例如 LinkedHashSet 和 SortedSet等)所以 Multiset 占据了 List 和 Set 之间的一个灰色地带:允许重复,但是不保证顺序。事实上,Multiset 并没有实现 java.util.Set 接口,它更像是一个 Bag。普通的 Set 就像这样:[car, ship, bike],而 Multiset 会是这样:[car x 2, ship x 6, bike x 3]

1、使用场景

常见使用场景:Multiset 有一个有用的功能,就是跟踪每种对象的数量,所以你可以用来进行数字统计。 常见的普通实现方式如下:

public void wordCounts(List words) {
    Map<String, Integer> counts = new HashMap<String, Integer>();
    for (String word : words) {
        Integer count = counts.get(word);
        if (count == null) {
            counts.put(word, 1);
        } else {
            counts.put(word, count + 1);
        }
    }
}

如果我们需要得到某个单词(比如good)的出现次数,我们可能这么写:

int goodCount = counts.get("good");

很麻烦对吗?而且Map中的 get(E key) 的含义都不那么明显。那如果我们用 Multisets 来看看:

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

Multiset countMultiset = HashMultiset.create();
countMultiset.addAll(words);

很简单吧?甚至连循环都不需要。那么我们怎么得到某个单词(比如good)的出现次数?很简单:

int goodCount= countMultiset.count("good");

在 Multiset 中提供了一个 count(Object element) 方法,得到某个对象在 Multiset 中出现的次数,这个显然比在 Map里面调 get 的可读性好多了,不是吗?

注意: Multiset 提供 setCount(E, int)方法,可以修改元素 E 在 Multiset 中的次数,但是不能把元素出现的次数修改为负数和大于 Integer.MAX_VALUE 的值。否则将会抛出异常。

2、Multiset 不是 Map

Multiset 也不是 Map<E, Integer> 类型的结构, 我们可以用 Map<E, Integer> 来实现 Multiset,但是利用 Map<E,Integer> 实现 Multiset 和 Guava 的实现还是有很大的区别的,主要表现如下:

  • Multiset 中的元素出现的次数只能为正数,如果E的出现次数为0,那么E将不出现在multiset中,是不能在elementSet()和entrySet()的视图中;

  • multiset.size() 返回这个集合的大小,相当于在 multiset 中元素的出现的总数。如果想得到 multiset 中不同元素出现的总数,可以利用 elementSet().size() 来实现;

  • multiset.iterator() 可以遍历 multiset 中的所有元素,所以 iteration 遍历的次数就等于 multiset.size()

  • Multiset 支持添加、删除元素,设置元素出现的次数 setCount(elem, 0) 相当于移除elem的所有元素;

  • multiset.count(elem) 方法中的 elem 如果没有出现在 Multiset 中,那么它的返回值永远都是0。

常用的实现了 Multiset 接口的类有:

  • HashMultiset:元素存放于 HashMap

  • LinkedHashMultiset:元素存放于 LinkedHashMap,即元素的排列顺序由第一次放入的顺序决定

  • TreeMultiset:元素被排序存放于TreeMap

  • EnumMultiset:元素必须是 enum 类型

  • ImmutableMultiset:不可修改的 Mutiset

3、Multiset 的各种实现

Guava 提供了多种 Multiset 的实现,大致对应 JDK 中 Map 的各种实现:

Map对应的 Multiset是否支持null元素
HashMapHashMultiset
TreeMapTreeMultiset是(如果comparator支持的话)
LinkedHashMapLinkedHashMultiset
ConcurrentHashMapConcurrentHashMultiset
ImmutableMapImmutableMultiset

四、示例

public static void main(String args[]){
    // 创建 multiset 集合
    Multiset<String> multiset = HashMultiset.create();
    multiset.add("a");
    multiset.add("b");
    multiset.add("c");
    multiset.add("d");
    multiset.add("a");
    multiset.add("b");
    multiset.add("c");
    multiset.add("b");
    multiset.add("b");
    multiset.add("b");

    // 个数
    System.out.println("Occurrence of 'b' : " + multiset.count("b"));
    System.out.println("Total Size : " + multiset.size());

    // 遍历
    Set<String> set = multiset.elementSet();
    System.out.print("Set [");
    for (String s : set) {
        System.out.print(s);
    }
    System.out.println("]");

    // 使用迭代器
    Iterator<String> iterator = multiset.iterator();
    System.out.print("MultiSet [");
    while (iterator.hasNext()) {
        System.out.print(iterator.next());
    }
    System.out.println("]");

    // 不同元素的个数
    System.out.println("MultiSet [");
    for (Multiset.Entry<String> entry : multiset.entrySet()) {
        System.out.println("    Element: " + entry.getElement() + ", Occurrence(s): " + entry.getCount());
    }
    System.out.println("]");

    // 删除元素
    multiset.remove("b", 2);

    // 查找元素
    System.out.println("Occurence of 'b' : " + multiset.count("b"));
}

结果

Occurrence of 'b' : 5
Total Size : 10
Set [abcd]
MultiSet [aabbbbbccd]
MultiSet [
    Element: a, Occurrence(s): 2
    Element: b, Occurrence(s): 5
    Element: c, Occurrence(s): 2
    Element: d, Occurrence(s): 1
]
Occurence of 'b' : 3

五、相关文章



未经允许请勿转载:程序喵 » Google Guava 快速入门 —— 【新集合】Multiset 类

点  赞 (0) 打  赏
分享到: