资讯专栏INFORMATION COLUMN

浅析guava容器multimap

yy13818512006 / 3004人阅读

摘要:它主要做了件事初始化容器,并将元素添加到容器里维护这样我们再调用的方法直接就返回了,不需要再次遍历和统计的过程。维护实时的维护,及时删除总结整体上是对底层的二次封装,很好的处理了各种细节,比如子容器的判空处理,的计算效率,的维护等。

在日常开发中我们通常有需要对 List 容器进行分组的情况,比如对下面的list数据根据name字段来进行分组:

[
    {
        "date":"2018-01-31",
        "name":"wuzhong",
        "socre":0.8
    },
    {
        "date":"2018-01-30",
        "name":"wuzhong",
        "socre":0.9
    },
    {
        "date":"2018-01-31",
        "name":"wuzhong2",
        "socre":0.8
    }
]

通常我们的做法可能很自然的想到 Map> 的结构,比如代码如下:

Map> map = new HashMap<>();
for (Item item : list){
  List tmp = map.get(item.getName());
  if (null == tmp){
      tmp = new ArrayList<>();
      map.put(item.getName(),tmp);
  }
  tmp.add(item);
}

很简单, 但是代码量有点多,特别是需要判断List为null并初始化。

再用guava实现上述的功能:

Multimap multiMap = ArrayListMultimap.create();
for (Item item : list){
    multiMap.put(item.getName(),item);
}

代码量直接减少了一半...

怎么实现的

我们直接跟着 ArrayListMultimap 的源码进去,发现其父类和我们最初的设计一样,也是用了 Map> 作为数据的容器,但是多了一个 totalSize 的字段。

abstract class AbstractMapBasedMultimap extends AbstractMultimap
    implements Serializable {
  private transient Map> map;
  private transient int totalSize;

接着我们继续去看put方法的具体实现。

public boolean put(@Nullable K key, @Nullable V value) {
  Collection collection = map.get(key);
  if (collection == null) {
    collection = createCollection(key);
    if (collection.add(value)) {
      totalSize++;
      map.put(key, collection);
      return true;
    } else {
      throw new AssertionError("New Collection violated the Collection spec");
    }
  } else if (collection.add(value)) {
    totalSize++;
    return true;
  } else {
    return false;
  }
}

它主要做了2件事:

初始化容器,并将元素添加到容器里

维护 totalSize

这样我们再调用 multimap.size()的方法直接就返回了,不需要再次遍历和统计的过程。

疑问

multimap 里 public List get(@Nullable K key) 这个方法返回的是个List容器,如果我们直接对他操作,是不是也会影响totalsize呢?

Collection wuzhong2 = multiMap.get("wuzhong2");
wuzhong2.clear();
System.out.println(multiMap.size());     //输出2
System.out.println(multiMap.keySet());   //输出 wuzhong

结果是显而易见的,对guava返回的容器进行的操作的确是会影响它的宿主对象的。

具体的源码可以看下 com.google.common.collect.AbstractMapBasedMultimap.WrappedList ,他用了代理模式,底层还是用了一个 Collection 容器。

private class WrappedCollection extends AbstractCollection {
    final K key;
    Collection delegate;
    final WrappedCollection ancestor;
    final Collection ancestorDelegate;
    
    public void clear() {
      int oldSize = size(); // calls refreshIfEmpty
      if (oldSize == 0) {
        return;
      }
      delegate.clear();
      totalSize -= oldSize;    //维护实时的totalsize
      removeIfEmpty(); //      //维护keyset,及时删除
    }
    
总结

multimap 整体上是对java底层api的二次封装,很好的处理了各种细节,比如子容器的判空处理,totalsize的计算效率, keys 的维护等 。 在接口的易用性上也非常贴合开发者。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68398.html

相关文章

  • [Java] 浅析Google Guava Multimap

    摘要:类关系实现方法是以为的特定实现,这个类中没有太多的实际代码,主要是方法中特定的产生一个作为。是的一个专有版本,这个类和接口一起,将的方法都重写为。则是所有以为核心的的基本实现,这里实现了所有的方法,是最重要的一部分。 类关系 ArrayListMultiMap.java Multimap | | AbstractMultimap Serializa...

    yiliang 评论0 收藏0
  • 近几个月Github上最热门的Java项目一览

    摘要:今天逛了逛,顺手精选出了一下近几个月以来上最热门的个项目。相关阅读正式开源,帮助应用快速容器化未来可能会上热门的项目地址介绍哈哈,皮一下很开心。这是我自己开源的一份文档,目前仍在完善中,欢迎各位英雄好汉一起完善。 showImg(https://segmentfault.com/img/remote/1460000015766827?w=391&h=220);今天逛了逛Github,顺...

    cyqian 评论0 收藏0
  • eclipse collections入门

    摘要:配合一下方法使用类似的方法,用于提取一个里头的一个属性出来。当然,也可以简写为主要用来过滤集合。配合使用功能与相同,只是把该筛选条件内置在中然后这里直接使用,传入参数与功能相反集合分区只取出一个符合条件的计数与条件满足判断其他转参考 Function 配合一下方法使用: collect flatCollect groupBy minBy maxBy toSortedListBy so...

    LeexMuller 评论0 收藏0
  • 《java 8 实战》读书笔记 -第四章 引入流

    摘要:第四章引入流一什么是流流是的新成员,它允许你以声明性方式处理数据集合通过查询语句来表达,而不是临时编写一个实现。 第四章 引入流 一、什么是流 流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。就现在来说,你可以把它们看成遍历数据集的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码。 下面两段代码都是用来返回低...

    jeyhan 评论0 收藏0
  • EventBus原理

    摘要:实现了观察者模式,使用方法非常简单,可参考有用的二这篇文章主要讲解的实现原理。一言以蔽之内部有一个,当时往中增加一个元素为事件的类型,为观察者,时根据事件类型找到观察者之后,对其反射调用。 EventBus实现了观察者模式,使用方法非常简单,可参考:有用的Guava(二) 这篇文章主要讲解EventBus的实现原理。一言以蔽之:EventBus内部有一个map,当register时往m...

    lsxiao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<