guava 集合

本文介绍了 Guava 库中的多种集合工具类,包括 Multimap、BiMap、Table、Multiset 等,详细解释了它们的特点及应用场景,并通过实例展示了如何使用这些工具类简化常见的集合操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Multimap

我们一定会接触到这样的业务产生这样的结构:map<string,<list<..>>>,有的时候可以利用面向对象的方法避开这样的写法,但是有的时候只能这样,代码结构局很不美观。Multimap可以解决。
Multimap不是map
普通的map可以多个键对应一个值,而不能多个值对应一个键。可以理解为一对多的形式。而Multimap可以做到多对多的形式。一般使用ListMultimap和SetMultimap将值映射为list和set。
Multimap可以理解为 a-1,a-2,a-3,b-4,c-5或者理解为a-{1,2,3},b-4,c-5。
正常理解为第一种方式,但是Multimap返回的视图是按照第二种的方式,即key为单个元素,value是一个集合。

它有几个常用的方法:
put(k,v)添加一个简单的映射。
putAll(k,iterable)添加一组映射。它们的键是一个。
remove,removeAll同理。
它有几个视图:
entries:所有的键值映射,包括重复的。
keySet:所有不同的键的集合,这个很常用。
keys:所有的键,出现次数即为它对应的映射数。
values()、asmap()等。

ListMultimap<Integer, Object> multimap = ArrayListMultimap.create();
multimap.put(1, "c");
multimap.put(1, "v");
multimap.put(2, "x");
for (Integer key : multimap.keySet()) {
  System.out.println(multimap.get(key));
}

输出结果是两个list集合。


2、BiMap

有的时候要维护一个双向映射的关系,不知道有没有什么好的方法,普通的方法就是维护两个map,保持他们数据的同步,但是这样开销很大,也容易出错。guava的BiMap可以解决这样的问题。
通过源码查看BiMap是继承Map的,多以BiMap是一个map。

//bimap用于维护键值双向映射的两个map完成的功能。
BiMap<Integer, String> biMap = HashBiMap.create();
biMap.put(1, "a");
biMap.put(2, "b");
int a = biMap.inverse().get("a");
System.out.println(a);
//会抛出异常,a已经存在。若强制put,使用forceput。
//biMap.put(3,"a");
biMap.forcePut(3,"a");//覆盖之前的1
int b = biMap.inverse().get("a");
System.out.println(b);

biMap.inverse()的返回结果可以用map来盛放,这样很方便。


3、Table

有时候要维护二重索引,就要使用map<string,map<string,int>> 这样的结构,guava提供了Table的结构简化这种结构。

Table<String,String,Integer> table = HashBasedTable.create();
    table.put("a","b",1);
    table.put("a","c",2);
    table.put("b","c",3);
    System.out.println(table.cellSet());
    System.out.println(table.rowKeySet());
    System.out.println(table.columnKeySet());
    System.out.println(table.rowMap());
    System.out.println(table.columnMap());
    System.out.println(table.column("b"));
    System.out.println(table.row("a"));

理解起来比较简单,输出结果为:
[(a,b)=1, (a,c)=2, (b,c)=3]
[a, b]
[b, c]
{a={b=1, c=2}, b={c=3}}
{b={a=1}, c={a=2, b=3}}
{a=1}
{b=1, c=2}


4、Multiset

Multiset也不是set
因为它违背了set最重要的一个属性,无重复元素。

查看一个集合中每个元素出现的次数,一般会使用这种方式:

List<String> wordLost = Lists.newArrayList("a", "b", "c", "b", "a");
    Map<String, Integer> map = new HashMap<>();
    for (String word : wordLost) {
      if (map.get(word) == null) {
        map.put(word, 1);
      } else {
        map.put(word, map.get(word) + 1);
      }
    }
    System.out.println(map.get("a"));

但是利用Multiset可以很简单:

    HashMultiset<String> multiset = HashMultiset.create();
    multiset.addAll(wordLost);
    System.out.println(multiset.count("a"));

只用了3行代码就可以快速查看元素的个数,下面测试了它的几个方法:

    HashMultiset<String> multiset = HashMultiset.create();
    multiset.addAll(wordLost);
    System.out.println(multiset.count("a"));
    System.out.println(multiset.size());
    System.out.println(multiset.elementSet());
    Set set = multiset.elementSet();
    System.out.println(multiset.entrySet());
    multiset.add("a", 1);
    System.out.println(multiset.entrySet());
    multiset.setCount("a", 0);
    System.out.println(multiset.entrySet());

首先Multiset.count()方法可以查看指定元素的个数。
Multiset.size()返回所有元素个数,算上重复的元素。
Multiset.elementSet()返回所有不重复的元素,返回结果可以用Set盛放。
Multiset.entrySet()返回元素以及他的个数。
上述代码输出结果为:

2
5
[a, b, c]
[a x 2, b x 2, c]
[a x 3, b x 2, c]
[b x 2, c]

5、Iterables

List<String> list = Lists.newArrayListWithExpectedSize(1);
    list.add("a");
    List<String> list1 = Lists.newArrayListWithCapacity(1);
    System.out.println(Iterables.frequency(list, "a"));
    System.out.println(Iterables.getFirst(list1,"b"));
    System.out.println(Iterables.elementsEqual(list1, list));

上述代码输出结果为:

1
b
false

Iterables的frequency方法也可以返回集合中的元素个数。

实际编写代码过程中,会遇到get(0)的需求,就是拿list集合的第一元素,或者任意一个元素,这样写逻辑没有任何问题,但是出现索引0就是不美观,而且必须有相应的非空判断才能避免get(0)的空指针。guava提供了getFirst方法优雅的解决问题,还可以预防的加上如果为空的默认值。

elementsEqual方法提供比较集合内部元素是否相同的方法。


6、Lists

List<Integer> ints= Lists.newArrayList(1,2,3,4);
List<Integer> ints2 = Lists.reverse(ints);
System.out.println(ints2);
List<List<Integer>> ints3 = Lists.partition(ints, 2);
System.out.println(ints3);

Lists为guava的一个比较好用的类,实际写代码的时候都会习惯用Lists去申请一个list集合。
上述代码输出为:

[4, 3, 2, 1]
[[1, 2], [3, 4]]

reverse方法返回list的倒序,partition方法将list分割成每两个元素为一个单位的集合的集合。


7、Sets

Set<String> set = ImmutableSet.of("a", "b", "c");
Set<String> set1 = ImmutableSet.of("a", "c");
//交集
Set<String> interSet = Sets.intersection(set1, set);
System.out.println(interSet);
//笛卡尔积
System.out.println(Sets.cartesianProduct(set, set1));

ImmutableSet代表不可变的set,平时如果一个集合不会变,最好申请为Immutable的,guava提供了一些方法。
Sets.intersection返回两个set的交集,还有一些别的操作set的方法。
Sets.cartesianProduct返回两个set的笛卡尔积,这里的set就是数学的集合。


8、Maps

(1)、Maps.uniqueIndex用于一组对对象的一个属性值特殊,可以唯一标识一个对象,这里是字符串的长度。返回的map的键是function的返回类型,值是相应的元素 ,返回的就是Map类型。
返回的map可以按照属性值查找元素。

List<String> stringList = Lists.newArrayList("a", "ab", "abc");
Map<Integer, String> map1 = Maps.uniqueIndex(stringList, new Function<String, Integer>() {
      @Override
      public Integer apply(String input) {
        return input.length();
      }
    });
System.out.println(map1);

输出的结果是:

{1=a, 2=ab, 3=abc}

但是当属性值不是唯一的时候:就要使用MultiMap了

List<String> stringList1 = Lists.newArrayList("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
ListMultimap<Integer, String> ListMultimap = Multimaps.index(stringList1, new Function<String, Integer>() {
      @Override
      public Integer apply(String input) {
        return input.length();
      }
    });
System.out.println(ListMultimap);

输出的结果是:

{4=[zero, four, five, nine], 3=[one, two, six], 5=[three, seven, eight]}

(2)、比较两个map的内容区别:

    Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3, "d", 4);
    Map<String, Integer> right = ImmutableMap.of("c", 1, "b", 2, "a", 3, "e", 5);
    MapDifference<String, Integer> diff = Maps.difference(left, right);
    System.out.println(diff.entriesInCommon());
    System.out.println(diff.entriesDiffering());
    System.out.println(diff.entriesOnlyOnLeft());
    System.out.println(diff.entriesOnlyOnRight());

entriesInCommon方法返回两个map的相同的映射
entriesDiffering方法返回两个map键相同,值不同的映射
entriesOnlyOnLeft方法返回左面map特有的映射
entriesOnlyOnRight方法返回右面map特有的映射
输出的结果是:

{b=2}
{a=(1, 3), c=(3, 1)}
{d=4}
{e=5}

9、Multimaps

(1)、反转Multimap

    ArrayListMultimap<String, Integer> arrayListMultimap = ArrayListMultimap.create();
    arrayListMultimap.putAll("b", Ints.asList(2, 4, 6));
    arrayListMultimap.putAll("a", Ints.asList(4, 2, 1));
    arrayListMultimap.putAll("c", Ints.asList(2, 5, 3));
    System.out.println(arrayListMultimap);
    TreeMultimap<Integer, String> treeMultimap = Multimaps.invertFrom(arrayListMultimap, TreeMultimap.create());
    System.out.println(treeMultimap);

输出结果为:

{a=[4, 2, 1], b=[2, 4, 6], c=[2, 5, 3]}
{1=[a], 2=[a, b, c], 3=[c], 4=[a, b], 5=[c], 6=[b]}

(2)、把map转化为multimap,实现从多对一(多个键对应一个值)到一对多(一个键对应多个值)的转化。

    Map<String, Integer> normalMap = ImmutableMap.of("a", 1, "b", 1, "c", 2);
    SetMultimap<String, Integer> setMultimap = Multimaps.forMap(normalMap);
    TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(setMultimap, TreeMultimap.create());
    System.out.println(inverse);

输出为:

{1=[a, b], 2=[c]}

10、PeekingIterator

PeekingIterator有一个在循环拿取元素的时候先看一下下一个元素的功能。
用它来实现去除一个连续重复的数字。

    List<Integer> source = Lists.newArrayList(1, 1, 1, 2, 3, 4, 5, 5, 5, 5, 6, 6, 7);
    List<Integer> result = Lists.newArrayList();
    PeekingIterator<Integer> iterator = Iterators.peekingIterator(source.iterator());
    while (iterator.hasNext()) {
      Integer current = iterator.next();
      while (iterator.hasNext() && iterator.peek().equals(current)) {
        iterator.next();
      }
      result.add(current);
    }
    System.out.println(result);

输出结果为:

[1, 2, 3, 4, 5, 6, 7]

guava是高度的遵循jdk的风格,接口规范去优化一部分常用的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值