Guava

作者日期邮箱
潘顾昌2019/10/05guchang.pan@hand-china.com

Guava

1 基本工具

一、Optional

针对Java开发中null的问题,guava设计了Optional类。虽然util包下也有自带的Optional类,但是Guava对其做了更好的处理。Optional 用来表示可能为null的T类型的引用,两个实现类Present(存在)和Absent(不存在)。
那么Optional究竟有什么用呢,我们来看一下主要的方法:

Optional.fromNullable(T) 创建指定引用的Optional实例,若引用为null则表示缺失
boolean isPresent() 如果Optional包含非null的引用(引用存在),返回true

String s1 = null;
String s2 = "1";
Optional opt1 = Optional.fromNullable(s1);
Optional opt2 = Optional.fromNullable(s2);
System.out.println(opt1.isPresent());  // false
System.out.println(opt2.isPresent());  // true

T get() 返回Optional所包含的引用,若引用缺失,则抛出java.lang.IllegalStateException
T or(T) 返回Optional所包含的引用,若引用缺失,返回指定的值
T orNull() 返回Optional所包含的引用,若引用缺失,返回null

// 紧接着上面的例子
System.out.println(opt1.or("0"));   // 0
System.out.println(opt1.orNull());  // null
System.out.println(opt2.get());     // 1
System.out.println(opt2.or("0"));   // 1
System.out.println(opt2.orNull());  // 1

Optional.of(T) 创建指定引用的Optional实例,若引用为null则快速失败

Optional.of("0");
Optional.of(null);  // NullPointerException

Optional存在的意义是什么?看下官方的解释:

使用Optional除了赋予null语义,增加了可读性,最大的优点在于它是一种傻瓜式的防护。Optional迫使你积极思考引用缺失的情况,因为你必须显式地从Optional获取引用。直接使用null很容易让人忘掉某些情形,尽管FindBugs可以帮助查找null相关的问题,但是我们还是认为它并不能准确地定位问题根源。
    如同输入参数,方法的返回值也可能是null。和其他人一样,你绝对很可能会忘记别人写的方法method(a,b)会返回一个null,就好像当你实现method(a,b)时,也很可能忘记输入参数a可以为null。将方法的返回类型指定为Optional,也可以迫使调用者思考返回的引用缺失的情形。
    总的来说Optional实际上就是一个提醒,让开发者时刻注意null。

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/5 16:50
 */
public class OptionalTest {
    public static void main(String[] args) {
        String s1 = null;
        String s2 = "1";
        Optional opt1 = Optional.fromNullable(s1);
        Optional opt2 = Optional.fromNullable(s2);
        Object o = opt1.or(15);
        Object o1 = opt2.or(15);
        System.out.println(o);
        System.out.println(o1);
        Object o2 = opt1.orNull();
        System.out.println(o2);
    }
}

二、前置条件

Guava封装好了几种前置条件的实用方法,能够让判断条件更简单。
每种方法都有3个重载函数:
● 没有额外参数,只抛出异常,无错误信息
● 有一个Object类型的额外参数,通过toString方法输出错误信息
● 有一个String对象和Object数组作为额外参数,String中通过’%s’占位符依次输出数组中的参数值

方法声明描述失败抛出异常
checkArgument(boolean)检查boolean是否为true,用于参数检查IllegalArgumentException
checkState(boolean)检查对象的某些状态IllegalStateException
checkNotNull(T)检查T的实例是否为null,直接返回该实例NullPointerException
checkElementIndex(int index, int size)检查索引是否有效(index>=0&&index<size)IndexOutOfBoundsException
checkPositionIndex(int index, int size)检查位置是否有效(index>=0&&index<=size)IndexOutOfBoundsException
checkPositionIndexes(int start, int end, int size)检查位置在[start, end]是否有效IndexOutOfBoundsException

有这些前置条件可以省去很多重复的判断代码。

// 直接 static 引入即可
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

checkNotNull(reference, ...);
checkArgument(expression, ...);
checkState(expression, ...);
/**
 * @Author: 潘顾昌
 * @Date: 2019/10/5 16:50
 */
public class OptionalTest {

    static void myCheckNotNull(){
        String str=null;
        String aNull = checkNotNull(str, "对象%s非空",11);
        Console.log(aNull);
    }

    public static void main(String[] args) {
        // 1.检查非空
        myCheckNotNull();
    }
}
static void myCheckArgument(){
        boolean str=false;
        checkArgument(5<4, "%s不大于%s","张三", "李四");
    }

    public static void main(String[] args) {
        // 1. 检查非空
        /* myCheckNotNull(); */
        // 2. 检查表达式正确性
        myCheckArgument();
    }

/*
Exception in thread "main" java.lang.IllegalArgumentException: 张三不大于李四
*/

三、链式比较器ComparisonChain

package com.pigic.guavas.bean;

import cn.pigicutils.core.comparator.CompareUtil;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;
import lombok.Data;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/8 21:24
 */
@Data
public class People implements Comparable<People>{
    private Long peopleId;
    private String peopleName;
    private Long peopleAge;

    @Override
    public int compareTo(People o) {
        return ComparisonChain.start()
        .compare(peopleAge, o.getPeopleAge())
        //nullsLast null值大一点
        .compare(peopleName, o.getPeopleName(), Ordering.natural().nullsLast())
        .compare(peopleId, o.getPeopleId())
        .result();
    }
}
static void myCompare(){
        People people = new People();
        people.setPeopleId(15L);
        people.setPeopleAge(12L);
        people.setPeopleName("张三丰");
        People people2 = new People();
        people2.setPeopleId(16L);
        people2.setPeopleAge(12L);
        people2.setPeopleName(null);
        int i = CompareUtil.compare(people, null, true);
        int i1 = CompareUtil.compare(null, people, true);
        int i2 = CompareUtil.compare(null, null, true);
        int i3 = CompareUtil.compare(people, people2, true);
        Console.log(i,i1,i2,i3);
    }
    public static void main(String[] args) {
        myCompare();
    }

/*
-1
1
0
-1
*/

四、Guava强大的比较器

首先"强大"两字来源于官网的标题,不过个人认为确实强大~~
通过源码可以看出Ordering实际上是Comparator的实例,并且拓展出了链式调用方法,使用起来非常方便。

  1. 创建排序
    ● natural() 对排序类型做自然排序
    ● usingToString() 按对象toString()方法做字典排序
    ● from(Comparator) 转化排序器
    除此外还可以直接继承Ordering:
Ordering<String> ordering = new Ordering<String>() {
  		@Override
  		public int compare(String left, String right) {
  			return left.compareTo(right);
  		}
  	};

链式调用方法
所谓链式调用就是由给定的排序器衍生出其他排序器

方法描述
reverse()倒叙排序
nullsFirst()排序中,把null值拍到最前
nullsLast()排序中,把null值拍到最后
compound(Comparator)合成比较器,处理当前排序器中的相等情况
lexicographical()返回按字典迭代的排序器
onResultOf(Function)对集合调用Function,再按返回值排序
int compare = Ordering.natural().nullsLast().compare(null, people2);

2 新集合类型

Guava在现有的JDK集合中有新增了Multiset、Multimap、BiMap、Table、ClassToInstanceMap、RangeSet、RangeMap等新集合。这些新集合能够跟JDK集合框架共存,并遵循JDK接口契约。所有新集合的构造器都进行了私有化处理,并通过静态函数生成实例。

一、聚合统计Multiset

Multiset多用于统计元素个数,例如统计一个句子中相同字母的个数。传统的方法就是依次遍历存储在Map<String, Integer>中,最后迭代输出,而有了Multiset,只需将字母传入构造器中,就会自动统计出来。

Multiset<String> multiset = HashMultiset.create();
String string = "hello world";
multiset = TreeMultiset.create(Lists.newArrayList(string.split("")));
Set<String> strings = multiset.elementSet();
for (String s : strings) {
	System.out.println(s + ": " + multiset.count(s));
}
//		 : 1
//		d: 1
//		e: 1
//		h: 1
//		l: 3
//		o: 2
//		r: 1
//		w: 1

package com.pigic.guavas;

import cn.pigicutils.core.lang.Console;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
import com.google.common.collect.Multiset;
import com.google.common.collect.TreeMultiset;

import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/8 22:28
 */
public class NewCollectionTest {
    public static void main(String[] args) {
        Multiset<String> multiset = null;
        String string = "hello world";
        // key排序
//        multiset = TreeMultiset.create(Lists.newArrayList(string.split("")));
        // key乱序
        multiset = HashMultiset.create(Lists.newArrayList(string.split("")));
        Set<String> elementSet = multiset.elementSet();
        Console.log(elementSet.size());
        for (String ele: elementSet){
            Console.logT("{}元素的个数为{}", ele, multiset.count(ele));
        }
    }
}

/*
8
 元素的个数为1
d元素的个数为1
e元素的个数为1
h元素的个数为1
l元素的个数为3
o元素的个数为2
r元素的个数为1
w元素的个数为1
*/
CopyOnWriteArrayList为什么并发安全且性能比Vector好
我知道Vector是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获得锁,性能就会大大下降,而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector,CopyOnWriteArrayList支持读多写少的并发情况。

二、一对多Mulitimap

Multimap对map提供了一对多的方式,也就是说一个键可对应多个值,相当于Map<K, List>或Map<K, Set>的格式,因此通过get(K)获得的结果是以集合的形式返回,即使没有对应的值,也会返回空集合,不存在null的情况。

Multimap<String, String> hashMultimap = HashMultimap.create();
hashMultimap.put("a", "1");   hashMultimap.put("a", "3");
hashMultimap.put("a", "2");   hashMultimap.put("a", "2");
hashMultimap.put("b", "1");

Multimap<String, String> arrayListMultimap = ArrayListMultimap.create();
arrayListMultimap.put("a", "1");   arrayListMultimap.put("a", "3");
arrayListMultimap.put("a", "2");   arrayListMultimap.put("a", "2");
arrayListMultimap.put("b", "1");

// HashMultimap 和 ArrayListMultimap 实现 Multimap
System.out.println(hashMultimap.get("a"));           // 结果:[1, 2, 3]。Set形式,值不会有重复
System.out.println(hashMultimap.get("b"));           // [1]
System.out.println(hashMultimap.get("1"));           // 结果:[]。没有对应,返回空集合
System.out.println(arrayListMultimap.get("a"));      // 结果:[1, 2, 2, 3]。ArrayList形式
System.out.println(arrayListMultimap.get("b"));      // [1]

System.out.println(arrayListMultimap.asMap());       // 结果:{a=[1, 2, 2, 3], b=[1]}。提供 Map&lt;K, Collection&lt;V>> 的形式
System.out.println(hashMultimap.asMap().values());   // 结果:[[1, 2, 3], [1]]。Map&lt;K, Collection&lt;V>>的values形式
System.out.println(arrayListMultimap.values());      // 结果:[1, 2, 2, 3, 1]。Multimap&lt;K, V>的values形式,将多个ArrayList&lt;V>合为一个Collection
System.out.println(hashMultimap.values());           // 结果:[1, 2, 3, 1]。将多个Set&lt;V>合为一个Collection
System.out.println(arrayListMultimap.keys());        // 结果:[a x 4, b]。keys()返回Multiset的类型
System.out.println(arrayListMultimap.keySet());      // [a, b]

三、双向映射BiMap

BiMap用于实现键值对的双向映射。当然也可以维护两个Map,但这样的操作太不方便了,而且极易出错。

BiMap<String, Integer> biMap = HashBiMap.create();
biMap.put("a", 1);
biMap.put("b", 2);
// biMap.put("c", 1);                 // throw IllegalArgumentException: value already present: 1
biMap.forcePut("c", 1);
System.out.println(biMap);            // 结果:{b=2, c=1}。之前a的键值被替换成了c
System.out.println(biMap.inverse());  // {2=b, 1=c}

从上例看出,当要将键映射到已存在的值上时,会抛IllegalArgumentException异常,但可以通过forcePut()强制替换,这样就可以保证键值的唯一性,在键值转换过程不会丢失数据或发生灵异事件。

BiMap的其他实现还有ImmutableBiMap、EnumBiMap、EnumHashBiMap,其中EnumBiMap的键值必须为枚举类型、EnumHashBiMap的键必须为枚举类型。

四、多映射表格Table

Multimap用于简化Map<K, Collection>的形式,但对于Map<R, Map<C, V>>这种格式的就需要用到Table来简化了。
与Multimap类似,Table也有转化为Map<R, Map<C, V>>的方法,下面是HashBasedTable的实现例子:

package com.pigic.guavas;

import cn.pigicutils.core.lang.Console;
import com.google.common.collect.*;

import java.util.Set;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/8 22:28
 */
public class NewCollectionTest {
    public static void main(String[] args) {
        Table<String, String, Integer> table = HashBasedTable.create();
        table.put("2","1", 15);
        table.put("2","2", 14);
        table.put("1","1", 12);
        table.put("1","2", 13);
        System.out.println(table);                    // {1={1=12, 2=13}, 2={1=15, 2=14}}
        System.out.println(table.rowMap());           // {1={1=12, 2=13}, 2={1=15, 2=14}}
        System.out.println(table.cellSet());          // [(1,1)=12, (1,2)=13, (2,1)=15, (2,2)=14]
        System.out.println(table.row("1"));  		  // {1=12, 2=13}
        System.out.println(table.values());           // [12, 13, 15, 14]
        Set<Table.Cell<String, String, Integer>> cells = table.cellSet();
        cells.forEach(cell->{
            /*
            (1,1)=12
            (1,2)=13
            (2,1)=15
            (2,2)=14
             */
            Console.log(cell);
        });
    }
}

五、 类型实例映射ClassToInstanceMap

ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象。
    ClassToInstanceMap实现了Map<Class<? extends B>, B>的形式,即一个映射B的子类型到对应实例的Map。这里的B是Map所支持类型的上界,看例子来理解下:

package com.pigic.guavas;

import cn.pigicutils.core.lang.Console;
import cn.pigicutils.core.lang.Dict;
import com.google.common.collect.MutableClassToInstanceMap;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 14:40
 */
public class ClassToInstanceMapTest {
    public static void main(String[] args) {
        MutableClassToInstanceMap<Object> instanceMap = MutableClassToInstanceMap.create();
        instanceMap.putInstance(Dict.class,Dict.create().set("name", "pgc"));
        instanceMap.putInstance(String.class, "张三");
        instanceMap.putInstance(String.class, "张三2");
        Dict dict = instanceMap.getInstance(Dict.class);
        String dict2 = instanceMap.getInstance(String.class);
        Console.log(dict);
        Console.log(dict2);
    }
}

ClassToInstanceMap只额外扩展了两个方法getInstance(Class)和putInstance(Class, T),用于类型的安全转换,避免强转导致的错误。
同样键是唯一的,当有重复的键存在时会覆盖前一个键的映射,且存放键的类型必须为List或List的子类。
ClassToInstanceMap的实现有 MutableClassToInstanceMap 和 ImmutableClassToInstanceMap。

MutableClassToInstanceMap 可多次putInstance相同key值,后者会覆盖前者。ImmutableClassToInstanceMap当put相同的key值会报错:Multiple entries with same key: class java.lang.String=张三2 and class java.lang.String=张三

六、比较集合范围RangeSet

RangeSet描述了一组不相连的、非空的区间。不只是对数字的操作,只要定义了排序规则都可以作为泛型放入进行比较。

package com.pigic.guavas.two;

import cn.pigicutils.core.lang.Console;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 15:05
 */
public class RangeSetTest {
    public static void main(String[] args) {
        RangeSet<Integer> treeRangeSet = TreeRangeSet.create();
        treeRangeSet.add(Range.closed(0,20));
        treeRangeSet.remove(Range.closed(3, 11));                    //  [[1‥3), (11‥20]]
        treeRangeSet.add(Range.openClosed(2, 5));                    //  [[1‥3), (3‥5], (11‥20]]
        System.out.println(treeRangeSet.contains(11));               //  false
        System.out.println(treeRangeSet.rangeContaining(4));         //  (3‥5]
        System.out.println(treeRangeSet.span());                     //  [1, 20]
        System.out.println(treeRangeSet);                            //  [[1‥3), (3‥5], (11‥20)]
        System.out.println(treeRangeSet.asRanges());                 //  [[1‥3), (3‥5], (11‥20)]
        System.out.println(treeRangeSet.complement());               //  [(-∞‥1), [3‥3], (5‥11], [20‥+∞)]
    }
}

七、比较集合范围映射RangeMap

RangeMap提供了不相交的、非空的区间到特定值的映射,和RangeSet不同的是RangeMap不会合并相邻的映射,即便相邻的区间映射到相同的值。

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo"); //  [[1‥10]=foo]
rangeMap.put(Range.open(3, 6), "bar");    //  [[1‥3]=foo, (3‥6)=bar, [6‥10]=foo]
rangeMap.put(Range.open(10, 20), "foo");  //  [[1‥3]=foo, (3‥6)=bar, [6‥10]=foo, (10‥20)=foo]
rangeMap.remove(Range.closed(5, 11));     //  [[1‥3]=foo, (3‥5)=bar, (11‥20)=foo]

RangeMap的实现有 TreeRangeMap 和 ImmutableRangeMap。

package com.pigic.guavas.two;

import cn.pigicutils.core.lang.Console;
import com.google.common.collect.*;

import java.util.Map;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 15:05
 */
public class RangeSetTest {
    public static void main(String[] args) {
        RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
        rangeMap.put(Range.closed(1, 10), "foo1"); //  [[1‥10]=foo]
        rangeMap.put(Range.open(3, 6), "bar");    //  [[1‥3]=foo, (3‥6)=bar, [6‥10]=foo]
        rangeMap.put(Range.open(10, 20), "foo");  //  [[1‥3]=foo, (3‥6)=bar, [6‥10]=foo, (10‥20)=foo]
        rangeMap.remove(Range.closed(5, 11));     //  [[1‥3]=foo, (3‥5)=bar, (11‥20)=foo]
        String s = rangeMap.get(4);
        Map<Range<Integer>, String> rangeStringMap = rangeMap.asMapOfRanges();
        Console.log(rangeMap);
        Console.log(rangeStringMap);
        Console.log(s);
    }
}

3 不可变集合

不可变集合就是在初始化时定义好数据,在之后的使用过程中不能再修改的集合。Guava对所有的JDK集合类型和新集合类型都封装了对应的不可变集合。但需要注意的是,所有Guava不可变集合的实现都不接受null值。

一、为什么使用不可变集合

Guava给出了使用原因:
不可变对象有很多优点,包括:
● 当对象被不可信的库调用时,不可变形式是安全的; 
● 不可变对象被多个线程调用时,不存在竞态条件问题
● 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
● 不可变对象因为有固定不变,可以作为常量来安全使用。

JDK也提供了Collections.unmodifiableXXX方法把集合包装为不可变形式,但我们认为不够好:
○ 笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;
○ 不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的;
○ 低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。

二、不可变集合的使用
1.通过 copyOf() 方法创建

ImmutableSortedSet<String> immutableSortedSet = ImmutableSortedSet.<String>copyOf(new String[]{"2", "1", "3"});  //  [1, 2, 3]

2.通过 of() 方法创建

ImmutableMap<String, Integer> immutableMap = ImmutableMap.<String, Integer>of("a", 2, "b", 1);  //  {a=2, b=1}

3.通过 Builder 创建

ImmutableSet<String> immutableSet = ImmutableSet.<String>builder().add("1").add("2").add("1").build();  //  [1, 2]

由上可以看出,对于有序不可变集合,在构造时就完成了排序;对于不重复的不可变集合,在构造时会自动去重。

ImmutableXXX.copyOf(ImmutableCollection)会试图对如下情况避免线性时间拷贝:
● 在常量时间内使用底层数据结构是可能的——例如,ImmutableSet.copyOf(ImmutableList)就不能在常量时间内完成。
● 不会造成内存泄露——例如,你有个很大的不可变集合ImmutableList hugeList,ImmutableList.copyOf(hugeList.subList(0, 10))就会显式地拷贝,以免不必要地持有hugeList的引用。
● 不改变语义——所以ImmutableSet.copyOf(myImmutableSortedSet)会显式地拷贝,因为和基于比较器的ImmutableSortedSet相比,ImmutableSet对hashCode()和equals有不同语义。
在可能的情况下避免线性拷贝,可以最大限度地减少防御性编程风格所带来的性能开销。

三、可变集合和不可变集合的关联

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fvGggOgZ-1594309581838)(…/Image/1571211838401.png)]

4 强大的集合工具

一、集合工具

通过 Lists.newArrayList(E… elements) 可以很方便的构建ArrayList集合去使用。除了List,Guava对所有的集合类型都有对应的封装,包括JDK没有的新集合类型,并且构造器支持多种类型的参数传递,光这一点就很强大了!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aaF17AIv-1594309581840)(…/Image/1571213347274.png)]

1.Lists

package com.pigic.guavas.four;

import cn.pigicutils.core.lang.Console;
import com.google.common.collect.Lists;

import java.util.List;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 16:09
 */
public class ColUtils {
    public static void main(String[] args) {
        List<Integer> list1 = Lists.newArrayList(0, 2, 5);
        List<Integer> list2 = Lists.newArrayList(3, 4);
// 以指定大小分割list
        System.out.println(Lists.partition(list1, 2));             // [[0, 2], [5]]
// list反转
        System.out.println(Lists.reverse(list1));                  // [5, 2, 0]
// 返回字符串的不可变列表
        System.out.println(Lists.charactersOf("123"));             // [1, 2, 3]
        List<Integer> integerList = Lists.transform(list1, i -> {
            return i + 1;
        });
        Console.log(integerList);
    }
}

2.Sets

package com.pigic.guavas.four;

import cn.pigicutils.core.lang.Console;
import com.google.common.collect.Sets;

import java.util.List;
import java.util.Set;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 16:23
 */
public class SetsTest {
    public static void main(String[] args) {
        Set<String> set1 = Sets.newHashSet("1", "2", "3", "4", "2", "3");  // [1, 2, 3, 4]
        Set<String> set2 = Sets.newHashSet("3", "4", "5", "6", "6");       // [3, 4, 5, 6]
// 计算两set的合集
        System.out.println(Sets.intersection(set1, set2));          //  [3, 4]
// 计算两set的差集
        System.out.println(Sets.difference(set1, set2));            //  [1, 2]
// 计算对称差集
        System.out.println(Sets.symmetricDifference(set1, set2));   //  [1, 2, 5, 6]
// 计算并集
        System.out.println(Sets.union(set1, set2));                 //  [1, 2, 3, 4, 5, 6]
// 计算所有子集
        System.out.println(Sets.powerSet(set1));                    //  powerSet({1=0, 2=1, 3=2, 4=3})
        System.out.println(Sets.newHashSet(Sets.powerSet(set1)));   //  [[], [1, 2], [1, 3], [2, 3], [1, 4], [2, 4], [3, 4], [1, 2, 3, 4], [1], [2], [3], [4], [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
// 计算笛卡尔积方法=
        Set<List<String>> lists = Sets.cartesianProduct(set1);
        Console.log(lists);
    }
}

3.Maps

package com.pigic.guavas.four;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;

import java.util.Map;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 21:40
 */
public class MapTest {
    public static void main(String[] args) {
        Map<Integer, String> map1 = ImmutableMap.of(1, "a", 2, "b", 3, "a");
        Map<Integer, String> map2 = ImmutableMap.of(2, "b", 3, "c", 4, "d");
        MapDifference<Integer, String> difference = Maps.difference(map1, map2);
// 键只存在左边的映射
        System.out.println(difference.entriesOnlyOnLeft());    //  {1=a}
// 键只存在右边的映射
        System.out.println(difference.entriesOnlyOnRight());   //  {4=d}
// 左、右键值对都相同的映射
        System.out.println(difference.entriesInCommon());      //  {2=b}
// 键相同但值不同的映射项
        System.out.println(difference.entriesDiffering());     //  {3=(a, c)}
// 左、右键值对是否全部相同
        System.out.println(difference.areEqual());             //  false

    }
}

4.Multisets

package com.pigic.guavas.four;

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

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 21:46
 */
public class MultiSetTest {

    public static void main(String[] args) {
        Multiset<String> multiset1 = HashMultiset.create(Lists.newArrayList("b", "b", "a"));                 //  [a, b x 2]
        Multiset<String> multiset2 = HashMultiset.create(Lists.newArrayList("b", "b", "b", "b", "b", "a"));  //  [a, b x 5]
// multiset1中是否包含所有multiset2中的元素
        System.out.println(multiset1.containsAll(multiset2));                         //  true
// 对于任意o,若 multiset1.count(o) >= multiset2.count(o),返回true
        System.out.println(Multisets.containsOccurrences(multiset1, multiset2));      //  false
// 计算multiset1和multiset2所有元素总和
        System.out.println(Multisets.sum(multiset1, multiset2));                      //  [a x 2, b x 7]
// 将元素按次数降序排序,返回不可变集合
        System.out.println(Multisets.copyHighestCountFirst(multiset1));               //  [b x 2, a]
// 对multiset1中的重复元素,仅在multiset2中删除相同个数
        Multisets.removeOccurrences(multiset2, multiset1);
        System.out.println(multiset2);    //  [b x 3]
// 修改multiset2,保证任意o满足 multiset2.count(o) <= multiset1.count(o)
        Multisets.retainOccurrences(multiset2, multiset1);
        System.out.println(multiset2);    //  [b x 2]
        System.out.println(multiset1);    //  [b x 2]

    }
}

5.Multimaps

package com.pigic.guavas.four;

import cn.pigicutils.core.lang.Dict;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimaps;

import java.util.Map;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 21:55
 */
public class MultiMapTest {
    public static void main(String[] args) {
        // forMap() 与 invertFrom()
        Map<Integer, String> map = ImmutableMap.of(1, "a", 2, "b", 3, "a");
        System.out.println(map);       //  {1=a, 2=b, 3=a}
        HashMultimap<String, Integer> multimap = Multimaps.invertFrom(Multimaps.forMap(map), HashMultimap.create());
        System.out.println(multimap);  //  {a=[1, 3], b=[2]}

    }
}

6.Tables

Table<String, String, Integer> hashTable = HashBasedTable.create();
hashTable.put("0", "0", 0);  hashTable.put("0", "1", 1);
hashTable.put("1", "0", 2);  hashTable.put("1", "1", 3);
hashTable.put("2", "0", 2);  hashTable.put("2", "1", 3);
System.out.println(hashTable.cellSet());                       //  [(0,0)=0, (0,1)=1, (1,0)=2, (1,1)=3, (2,0)=2, (2,1)=3]
System.out.println(Tables.transpose(hashTable).cellSet());     //  [(0,0)=0, (1,0)=1, (0,1)=2, (1,1)=3, (0,2)=2, (1,2)=3]

transpose()方法能够将 Table<R, C, V> 转为 Table<C, R, V>。用于有向图的反转。

二、 Iterables

Guava提供的工具方法更偏向于接受Iterable而不是Collection类型。因此,很多你期望的支持所有集合的操作都在Iterables类中。大多数Iterables方法有一个在Iterators类中的对应版本,用来处理Iterator。

package com.pigic.guavas.four;

import cn.pigicutils.core.lang.Dict;
import com.google.common.collect.*;

import java.util.List;
import java.util.Map;

/**
 * @Author: 潘顾昌
 * @Date: 2019/10/16 21:55
 */
public class MultiMapTest {
    public static void main(String[] args) {
        List<Integer> list1 = Lists.newArrayList(2, 2, 5, 7, 1);
        List<Integer> list2 = Lists.newArrayList(2, 5, 1, 7);
// 返回iterable中第一个元素,不存在返回默认值-1
        System.out.println(Iterables.getFirst(list2, -1));          //  2
// 返回iterable中最后一个元素,不存在抛出NoSuchElementException
        System.out.println(Iterables.getLast(list2));               //  7
// 判断iterable中是否包含元素
        System.out.println(Iterables.contains(list2, 3));           //  false
        System.out.println(Iterables.elementsEqual(list1, list2));  //  false
        System.out.println(Iterables.concat(list1, list2));         //  [2, 2, 5, 7, 1, 2, 5, 1, 7]
        System.out.println(Iterables.frequency(list1, 2));          //  2
        System.out.println(Iterables.limit(list1, 3));              //  [2, 2, 5]
        System.out.println(Iterables.partition(list1, 4));          //  [[2, 2, 5, 7], [1]]
        System.out.println(Iterables.paddedPartition(list1, 4));    //  [[2, 2, 5, 7], [1, null, null, null]]
        System.out.println(Iterables.skip(list1, 2));               //  [5, 7, 1]
// System.out.println(Iterables.getOnlyElement(list2));     //  java.lang.IllegalArgumentException: expected one element but was: <2, 5, 1, 7>

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潘顾昌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值