作者 | 日期 | 邮箱 |
---|---|---|
潘顾昌 | 2019/10/05 | [email protected] |
针对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&&indexIndexOutOfBoundsException |
|
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: 张三不大于李四
*/
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
*/
首先"强大"两字来源于官网的标题,不过个人认为确实强大~~
通过源码可以看出Ordering实际上是Comparator的实例,并且拓展出了链式调用方法,使用起来非常方便。
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);
Guava在现有的JDK集合中有新增了Multiset、Multimap、BiMap、Table、ClassToInstanceMap、RangeSet、RangeMap等新集合。这些新集合能够跟JDK集合框架共存,并遵循JDK接口契约。所有新集合的构造器都进行了私有化处理,并通过静态函数生成实例。
Multiset多用于统计元素个数,例如统计一个句子中相同字母的个数。传统的方法就是依次遍历存储在Map
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
*/
我知道Vector是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获得锁,性能就会大大下降,而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector,CopyOnWriteArrayList支持读多写少的并发情况。
Multimap对map提供了一对多的方式,也就是说一个键可对应多个值,相当于Map
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<K, Collection<V>> 的形式
System.out.println(hashMultimap.asMap().values()); // 结果:[[1, 2, 3], [1]]。Map<K, Collection<V>>的values形式
System.out.println(arrayListMultimap.values()); // 结果:[1, 2, 2, 3, 1]。Multimap<K, V>的values形式,将多个ArrayList<V>合为一个Collection
System.out.println(hashMultimap.values()); // 结果:[1, 2, 3, 1]。将多个Set<V>合为一个Collection
System.out.println(arrayListMultimap.keys()); // 结果:[a x 4, b]。keys()返回Multiset的类型
System.out.println(arrayListMultimap.keySet()); // [a, b]
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的键必须为枚举类型。
Multimap用于简化Map
与Multimap类似,Table也有转化为Map
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是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象。
ClassToInstanceMap实现了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描述了一组不相连的、非空的区间。不只是对数字的操作,只要定义了排序规则都可以作为泛型放入进行比较。
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提供了不相交的、非空的区间到特定值的映射,和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);
}
}
不可变集合就是在初始化时定义好数据,在之后的使用过程中不能再修改的集合。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)]
通过 Lists.newArrayList(E… elements) 可以很方便的构建ArrayList集合去使用。除了List,Guava对所有的集合类型都有对应的封装,包括JDK没有的新集合类型,并且构造器支持多种类型的参数传递,光这一点就很强大了!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aaF17AIv-1594309581840)(…/Image/1571213347274.png)]
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);
}
}
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);
}
}
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
}
}
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]
}
}
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]}
}
}
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
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>
}
}