崇祯五年十二月,余住西湖。大雪三日,湖中人鸟声俱绝。是日更定矣,余拏一小舟,拥毳衣炉火,独往湖心亭看雪。雾凇沆砀,天与云与山与水,上下一白。湖上影子,惟长堤一痕、湖心亭一点、与余舟一芥、舟中人两三粒而已。
到亭上,有两人铺毡对坐,一童子烧酒炉正沸。见余,大喜曰:“湖中焉得更有此人?”拉余同饮。余强饮三大白而别。问其姓氏,是金陵人,客此。及下船,舟子喃喃曰:“莫说相公痴,更有痴似相公者!”
– 《湖心亭看雪》(明)张岱
Guava项目是谷歌java的核心库,包括集合,缓存,原语,并发,注解,字符串,IO处理等,现在在github上有八千多个star,很早就听说过,但是一直没有去学习,是时候开始了,guava读[ˈɡwɑvə],番石榴 。最新的版本是19.0,发布于December 9, 2015。
那么搞起一个maven项目,就可以开始欣赏guava的代码了。
1 | <dependency> |
从哪里开始呢?不重要,重要的是你要action。前几日师弟问我了一个简单的问题“要读word进行字典排序,java中自然就会想到有序集合,把words存入TreeSet中,然后输出,不就是有序了吗,为何测试用例不通过;但是把words放入vector中,然后使用collections.sort方法就是OK的,为何?为何?”,后来得知问题的关键在于words可能会重复,那么TreeSet无法解决这种问题,TreeSet基于HashMap,没用C++里面的multimap,这就是问题的关键。所以如果遇到这种应用场景,就需要自己实现一个multimap,Guava中提供了,所以看看具体实现。
1 | public class LearnMultiMap { |
输出:
1 | [alpha, chownvon x 2, hello, vonzhou] |
初步跟踪了一下,没那么简单,我得静一会!
TreeMultiset: create,add方法。底层的操作就是AVL树的操作。
1 |
|
TreeMultiset.AvlNode: AvlNode的作用就是把一个Entry包装成一个tree中的节点,为了保证插入过程的平衡,还要在每个node中记录该子树的高度height,
1 | private static final class AvlNode<E> extends Multisets.AbstractEntry<E> { |
Multiset.AbstractEntry: 对Multiset.Entry中的equals,hashCode,toString这三个通用函数做了具体实现。
1 | abstract static class AbstractEntry<E> implements Multiset.Entry<E> { |
Multiset.Entry: 用于multiset的element-count pair,Multiset.entrySet()方法返回的就是关于该multiset的一个视图,然后用于遍历,虽然和Map.Entry没用关系,但是思路一样。
1 | interface Entry<E> { |
总结:
- 底层结构AVL
- 通过count记录重复元素,避免多次存储,可以想象着里面的tradeoff
vonzhou 2016-3-26 HUST