知识点
相关文章
更多最近更新
更多Guava学习笔记:Guava新增集合类型-Multiset
2019-03-08 21:43|来源: 网络
Guava引进了JDK里没有的,但是非常有用的一些新的集合类型。所有这些新集合类型都能和JDK里的集合平滑集成。Guava集合非常精准地实现了JDK定义的接口。Guava中定义的新集合有:
Multiset
SortedMultiset
Multimap
ListMultimap
SetMultimap
BiMap
ClassToInstanceMap
Table
Multiset集合
Multiset是什么?顾名思义,Multiset和Set的区别就是可以保存多个相同的对象。在JDK中,List和Set有一个基本的区别,就是List可以包含多个相同对象,且是有顺序的,而Set不能有重复,且不保证顺序(有些实现有顺序,例如LinkedHashSet和SortedSet等)所以Multiset占据了List和Set之间的一个灰色地带:允许重复,但是不保证顺序。
常见使用场景:Multiset有一个有用的功能,就是跟踪每种对象的数量,所以你可以用来进行数字统计。 常见的普通实现方式如下:
@Test public void testWordCount(){ String strWorld="wer|dffd|ddsa|dfd|dreg|de|dr|ce|ghrt|cf|gt|ser|tg|ghrt|cf|gt|" + "ser|tg|gt|kldf|dfg|vcd|fg|gt|ls|lser|dfr|wer|dffd|ddsa|dfd|dreg|de|dr|" + "ce|ghrt|cf|gt|ser|tg|gt|kldf|dfg|vcd|fg|gt|ls|lser|dfr"; String[] words=strWorld.split("\\|"); Map<String, Integer> countMap = new HashMap<String, Integer>(); for (String word : words) { Integer count = countMap.get(word); if (count == null) { countMap.put(word, 1); } else { countMap.put(word, count + 1); } } System.out.println("countMap:"); for(String key:countMap.keySet()){ System.out.println(key+" count:"+countMap.get(key)); } }
上面的代码实现的功能非常简单,用于记录字符串在数组中出现的次数。这种场景在实际的开发过程还是容易经常出现的,如果使用实现Multiset接口的具体类就可以很容易实现以上的功能需求:
public void testMultsetWordCount(){ String strWorld="wer|dfd|dd|dfd|dda|de|dr"; String[] words=strWorld.split("\\|"); List<String> wordList=new ArrayList<String>(); for (String word : words) { wordList.add(word); } Multiset<String> wordsMultiset = HashMultiset.create(); wordsMultiset.addAll(wordList);
for(String key:wordsMultiset.elementSet()){ System.out.println(key+" count:"+wordsMultiset.count(key)); } }
Multiset主要方法
Multiset接口定义的接口主要有:
add(E element) :向其中添加单个元素
add(E element,int occurrences) : 向其中添加指定个数的元素
count(Object element) : 返回给定参数元素的个数
remove(E element) : 移除一个元素,其count值 会响应减少
remove(E element,int occurrences): 移除相应个数的元素
elementSet() : 将不同的元素放入一个Set中
entrySet(): 类似与Map.entrySet 返回Set<Multiset.Entry>。包含的Entry支持使用getElement()和getCount()
setCount(E element ,int count): 设定某一个元素的重复次数
setCount(E element,int oldCount,int newCount): 将符合原有重复个数的元素修改为新的重复次数
retainAll(Collection c) : 保留出现在给定集合参数的所有的元素
removeAll(Collectionc) : 去除出现给给定集合参数的所有的元素
常用方法实例:
@Test public void testMultsetWordCount(){ String strWorld="wer|dfd|dd|dfd|dda|de|dr"; String[] words=strWorld.split("\\|"); List<String> wordList=new ArrayList<String>(); for (String word : words) { wordList.add(word); } Multiset<String> wordsMultiset = HashMultiset.create(); wordsMultiset.addAll(wordList); //System.out.println("wordsMultiset:"+wordsMultiset); for(String key:wordsMultiset.elementSet()){ System.out.println(key+" count:"+wordsMultiset.count(key)); } if(!wordsMultiset.contains("peida")){ wordsMultiset.add("peida", 2); } System.out.println("============================================"); for(String key:wordsMultiset.elementSet()){ System.out.println(key+" count:"+wordsMultiset.count(key)); } if(wordsMultiset.contains("peida")){ wordsMultiset.setCount("peida", 23); } System.out.println("============================================"); for(String key:wordsMultiset.elementSet()){ System.out.println(key+" count:"+wordsMultiset.count(key)); } if(wordsMultiset.contains("peida")){ wordsMultiset.setCount("peida", 23,45); } System.out.println("============================================"); for(String key:wordsMultiset.elementSet()){ System.out.println(key+" count:"+wordsMultiset.count(key)); } if(wordsMultiset.contains("peida")){ wordsMultiset.setCount("peida", 44,67); } System.out.println("============================================"); for(String key:wordsMultiset.elementSet()){ System.out.println(key+" count:"+wordsMultiset.count(key)); } }
输出:
de count:1 dda count:1 dd count:1 dfd count:2 wer count:1 dr count:1 ============================================ de count:1 dda count:1 dd count:1 dfd count:2 peida count:2 wer count:1 dr count:1 ============================================ de count:1 dda count:1 dd count:1 dfd count:2 peida count:23 wer count:1 dr count:1 ============================================ de count:1 dda count:1 dd count:1 dfd count:2 peida count:45 wer count:1 dr count:1 ============================================ de count:1 dda count:1 dd count:1 dfd count:2 peida count:45 wer count:1 dr count:1
说明:setCount(E element,int oldCount,int newCount): 方法,如果传入的oldCount和element的不一致的时候,是不能讲element的count设置成newCount的。需要注意。
Multiset不是Map
需要注意的是Multiset不是一个Map<E,Integer>,尽管Multiset提供一部分类似的功能实现。其它值得关注的差别有:
Multiset中的元素的重复个数只会是正数,且最大不会超过Integer.MAX_VALUE。设定计数为0的元素将不会出现multiset中,也不会出现elementSet()和entrySet()的返回结果中。
multiset.size() 方法返回的是所有的元素的总和,相当于是将所有重复的个数相加。如果需要知道每个元素的个数可以使用elementSet().size()得到.(因而调用add(E)方法会是multiset.size()增加1).
multiset.iterator() 会循环迭代每一个出现的元素,迭代的次数与multiset.size()相同。 iterates over each occurrence of each element, so the length of the iteration is equal to multiset.size().
Multiset 支持添加、移除多个元素以及重新设定元素的个数。执行setCount(element,0)相当于移除multiset中所有的相同元素。
调用multiset.count(elem)方法时,如果该元素不在该集中,那么返回的结果只会是0。
Multiset的实现
Guava提供了Multiset的多种实现,这些实现基本对应了JDK中Map的实现:
Map Corresponding Multiset Supports null elements
HashMap HashMultiset Yes
TreeMap TreeMultiset Yes (if the comparator does)
LinkedHashMap LinkedHashMultiset Yes
ConcurrentHashMap ConcurrentHashMultiset No
ImmutableMap ImmutableMultiset No
相关问答
更多-
主要是这样的:Multiset精确地遵循Collection集合,并且通常在其他JDK集合实用程序中扮演更好的角色。 此外,Multiset具有泛型支持,支持entrySet()方法和setCount方法,它们都不是由Bag提供的。 正如您可以清楚地看到的那样,它们的用途是相同的,但我希望Multiset在很多方面都能胜出。 Primarily this: Multiset follows the Collection contract precisely, and generally plays bett ...
-
在Guava中,如何使用单个元素和n次出现创建Multiset(In Guava, how to create a Multiset with a single element and n occurrences)[2023-12-12]
番石榴贡献者在这里。 坚持建设者。 它已经很简单地解决了这个问题,而且只需一行; 要求自己的特殊方法可能不是一个普遍的例子。 Guava contributor here. Stick with the builder. It already addresses the problem quite simply, and in a single line; it's probably not a common enough case to require its own special method. -
使用两种不同类型的Guava ListenableFutures的结果(Use the results of two Guava ListenableFutures of different types)[2022-03-23]
Runnable listener = new Runnable() { private boolean jobDone = false; @Override public synchronized void run() { if (jobDone || !(future1.isDone() && future2.isDone())) { return; } jobDone = true; // ... -
使用java 8流API看起来相当不错: java.util.Collection
idToDelete = currentB.stream() //get the stream .filter(b -> !newA.contains(b.getA())) // filter those b, whose A is in newA .map(b -> b.getA().id) // map transform to get just an Id ... -
使用Guava ForwardingList装饰集合的意外行为(Unexpected behaviour decorating a collection using Guava ForwardingList)[2022-06-25]
这种模式可行的唯一方法是,在创建装饰器后再也不会再次引用originalList 。 ForwardingList可能无法控制originalList发生的事情。 (没有装饰者可以。) 总的来说,你应该做的是创建一个工厂方法,它返回一个全新的装饰列表,永远不会让你访问原始列表。 The only way this pattern is going to work is if you never reference originalList again after you've created the dec ... -
严重的是,番石榴一切都很有用。 我一直在使用它一段时间,而且我仍然总是发现一些新的东西,它可以减少代码而不是用手做的。 有些事情其他人并没有真正提到我爱: Multimap只是很棒。 任何时候,您都可以使用Map
> ,使用多重图形,并为您自定义一个繁琐的检查映射到一个键的现有集合,如果不存在则创建和添加它。 Ordering对于构建Comparator是非常好的,它们的行为只是你想要的。 Maps.uniqueIndex和Multimaps.index :这些方法采 ... -
是否有针对Guava MultiSet和Table概念的scala替代品?(Is there a scala replacement for Guava MultiSet and Table concepts?)[2023-05-29]
您可以使用Map[(R, C), V]而不是Table和Map[T, Int]而不是Multiset 。 您还可以向Map[T, Int]添加辅助方法Map[T, Int]如下所示: implicit class Multiset[T](val m: Map[T, Int]) extends AnyVal { def setAdd(e: T, i: Int = 1) = { val cnt = m.getOrElse(e, 0) + i if (cnt <= 0) ... -
Iterable
> entriesSortedByCount = Multisets.copyHighestCountFirst(multiset).entrySet(); Iterable > entriesSortedByValue = ImmutableSortedMultiset.copyOf(multiset).entrySet(); 基本上,您只需要entrySet() ,而不是迭代Mu ... -
AbstractScheduledServiced实现Service 。 Service接口描述了生命周期方法,包括startAsync 。 ServiceState枚举文字包含有关其含义的文档。 处于NEW状态的服务(刚刚创建): 处于此状态的服务处于非活动状态。 它做的工作量极少,占用资源极少。 要使服务执行某些有用的操作,您必须将其转换为RUNNING状态 此状态下的服务正在运行。 这就是为什么你必须在它做任何事之前启动服务的原因。 我还建议不要从构造函数中调用startAsync,而是从创建MySe ...
-
如何使用Guava构建ConcurrentLinkedHashmap?(How to build a ConcurrentLinkedHashmap using Guava?)[2022-04-14]
ConcurrentLinkedHashmap API未移植到Guava 1:1,但CLHM的一些解决方案在MapMaker和Cache (使用CacheBuilder )中使用。 ConcurrentLinkedHashmap的作者Ben Manes回答了一个问题,可能会澄清您的疑问: ConcurrentLinkedHashMap已经集成到Guava中意味着什么? : 番石榴是长期替代品,大多数时候你应该使用它。 历史是ConcurrentLinkedHashMap找出算法,Guava包含它,然后专注于 ...