强大的 Guava 工具类
普通集合
List<String> list = Lists.newArrayList();
Set<String> set = Sets.newHashSet();
Map<String, String> map = Maps.newHashMap();
Set 取交集、并集、差集
HashSet<Integer> setA = Sets.newHashSet(1, 2, 3, 4, 5);
HashSet<Integer> setB = Sets.newHashSet(4, 5, 6, 7, 8);
Sets.SetView<Integer> union = Sets.union(setA, setB);
System.out.println("union:" + union);
Sets.SetView<Integer> difference = Sets.difference(setA, setB);
System.out.println("difference:" + difference);
Sets.SetView<Integer> intersection = Sets.intersection(setA, setB);
System.out.println("intersection:" + intersection);
map 取交集、并集、差集
HashMap<String, Integer> mapA = Maps.newHashMap();
mapA.put("a", 1);
mapA.put("b", 2);
mapA.put("c", 3);
HashMap<String, Integer> mapB = Maps.newHashMap();
mapB.put("b", 20);
mapB.put("c", 3);
mapB.put("d", 4);
MapDifference<String, Integer> differenceMap = Maps.difference(mapA, mapB);
Map<String, MapDifference.ValueDifference<Integer>> entriesDiffering = differenceMap.entriesDiffering();
//左边差集
Map<String, Integer> entriesOnlyLeft = differenceMap.entriesOnlyOnLeft();
//右边差集
Map<String, Integer> entriesOnlyRight = differenceMap.entriesOnlyOnRight();
//交集
Map<String, Integer> entriesInCommon = differenceMap.entriesInCommon();
System.out.println(entriesDiffering); // {b=(2, 20)}
System.out.println(entriesOnlyLeft); // {a=1}
System.out.println(entriesOnlyRight); // {d=4}
System.out.println(entriesInCommon); // {c=3}
不可变集合(immutable)
不可变集合的特性有:
- 在多线程操作下,是线程安全的;
- 所有不可变集合会比可变集合更有效的利用资源;
- 中途不可改变。
如果你的需求是想创建一个一经初始化后就不能再被改变的集合那么它适合你,因为这些工具类根本就没给你提供修改的 API,这意味着你连犯错误的机会都没有。
ImmutableList<Integer> iList = ImmutableList.of(12,54,87);
ImmutableSet<Integer> iSet = ImmutableSet.of(354,54,764,354);
ImmutableMap<String, Integer> iMap = ImmutableMap.of("k1", 453, "k2", 534);
以上 Immutable 开头的相关集合类的 add、remove 方法都被声明为 deprecated。当你手误点到了这些方法发现是 deprecated 的时候你不会还想着使用吧。
注意:每个Guava immutable集合类的实现都拒绝 null 值。
有趣的集合
MultiSet: 无序+可重复
我们映像中的 Set 应该是无序的,元素不可重复的。MultiSet 颠覆了三观,因为它可以重复。
定义一个 MultiSet 并添加元素:
Multiset<Integer> set = HashMultiset.create();
set.add(3);
set.add(3);
set.add(4);
set.add(5);
set.add(4);
你还可以添加指定个数的同一个元素:
set.add(7, 3);
这表示你想添加 3 个 7。
打印出来的 MultiSet 也很有意思:
[3 x 2, 4 x 2, 5, 7 x 3]
2 个 3,2 个 4, 一个 5, 3 个 7。
获取某个元素的个数:
int count = set.count(3);
这个工具类确实很有意思,帮我们实现了 word count。
Multimap :key 可以重复的 map
这个 map 也很有意思。正常的 map 为了区分不同的 key,它倒好,直接给你来一样的 key 。
Multimap<String, String> map = LinkedHashMultimap.create();
map.put("key", "haha");
map.put("key", "haha1");
Collection<String> key = map.get("key");
System.out.println(key);
使用很简单,用一个 key 可以获取到该 key 对应的两个值,结果用 list 返回。恕我无知,我还没想到这个 map 能够使用的场景。
工具类
JDK里大家耳熟能详的是Collections 这个集合工具类, 提供了一些基础的集合处理转换功能, 但是实际使用里很多需求并不是简单的排序, 或者比较数值大小, 然后 Guava 在此基础上做了许多的改进优化, 可以说是 Guava 最为成熟/流行的模块之一。
数组相关:Lists
集合相关:Sets
map 相关:Maps
连接符(Joiner)和分隔符(Splitter)#
Joiner 做为连接符的使用非常简单,下例是将 list 转为使用连接符连接的字符串:
List<Integer> list = Lists.newArrayList();
list.add(34);
list.add(64);
list.add(267);
list.add(865);
String result = Joiner.skipNulls().on("-").join(list);
System.out.println(result);
输出:34-64-267-865
将 map 转为自定义连接符连接的字符串:
Map<String, Integer> map = Maps.newHashMap();
map.put("key1", 45);
map.put("key2",234);
String result = Joiner.on(",").withKeyValueSeparator("=").join(map);
System.out.println(result);
输出:
key1=45,key2=234
分隔符 Splitter 的使用也很简单:
String str = "1-2-3-4-5-6";
List<String> list = Splitter.on("-").splitToList(str);
System.out.println(list);
输出:
[1, 2, 3, 4, 5, 6]
如果字符串中带有空格,还可以先去掉空格:
String str = "1-2-3-4- 5- 6 ";
List<String> list = Splitter.on("-").omitEmptyStrings().trimResults().splitToList(str);
System.out.println(list);
将 String 转为 map:
String str = "key1=54,key2=28";
Map<String,String> map = Splitter.on(",").withKeyValueSeparator("=").split(str);
System.out.println(map);
输出:
{key1=54, key2=28}
Comparator 的实现#
Java 提供了 Comparator 可以用来对对象进行排序。Guava 提供了排序器 Ordering 类封装了很多实用的操作。
Ordering 提供了一些有用的方法:
natural() 对可排序类型做自然排序,如数字按大小,日期按先后排序
usingToString() 按对象的字符串形式做字典排序[lexicographical ordering]
from(Comparator) 把给定的Comparator转化为排序器
reverse() 获取语义相反的排序器
nullsFirst() 使用当前排序器,但额外把null值排到最前面。
nullsLast() 使用当前排序器,但额外把null值排到最后面。
compound(Comparator) 合成另一个比较器,以处理当前排序器中的相等情况。
lexicographical() 基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>的排序器。
onResultOf(Function) 对集合中元素调用Function,再按返回值用当前排序器排序。
示例:
UserInfo build = UserInfo.builder().uid(234L).gender(1).build();
UserInfo build1 = UserInfo.builder().uid(4354L).gender(0).build();
Ordering<UserInfo> byOrdering = Ordering.natural().nullsFirst().onResultOf((Function<UserInfo, Comparable<Integer>>) input -> input.getGender());
System.out.println(byOrdering.compare(build1, build));
build 的 gender 大于 build1 的,所以返回 -1,反之返回 1。
统计中间代码运行时间#
Stopwatch 类提供了时间统计的功能,相当于帮你封装了调用 System.currentTimeMillis() 的逻辑。
Stopwatch stopwatch = Stopwatch.createStarted();
try {
//TODO 模拟业务逻辑
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
long nanos = stopwatch.elapsed(TimeUnit.SECONDS);
System.out.println(nanos);
Guava Cache - 本地缓存组件#
Guava Cache 在日常的使用中非常地频繁,甚至都没有意识到这是第三方提供的工具类而是把它当成了 JDK 自带的实现。
// LoadingCache是Cache的缓存实现
LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
//设置缓存大小
.maximumSize(1000)
//设置到期时间
.expireAfterWrite(10, TimeUnit.MINUTES)
//设置缓存里的值两分钟刷新一次
.refreshAfterWrite(2, TimeUnit.MINUTES)
//开启缓存的统计功能
.recordStats()
//构建缓存
.build(new CacheLoader<String, Object>() {
//此处实现如果根据key找不到value需要去如何获取
@Override
public Object load(String s) throws Exception {
return new Object();
}
//如果批量加载有比反复调用load更优的方法则重写这个方法
@Override
public Map<String, Object> loadAll(Iterable<? extends String> keys) throws Exception {
return super.loadAll(keys);
}
});

浙公网安备 33010602011771号