一、什么是 Guava
Guava 工程包含了若干被 Google 的 Java 项目广泛依赖的核心库,例如:集合【collections】、缓存【caching】、原生类型支持【primitives support】、并发库【concurrency libraries】、通用注解【common annotations】、字符串处理【string processing】、I/O 和 验证等等。所有这些工具每天都在被 Google 的工程师应用在产品服务中。
Guava 对 JDK 集合的扩展,这是 Guava 最成熟和为人所知的部分。
1、不可变集合:用不变的集合进行防御性编程和性能提升。
2、新集合类型:multisets, multimaps, tables,等。
3、强大的集合工具类:提供 java. Util. Collections 中没有的集合工具。
4、扩展工具类:让实现和扩展集合类变得更容易,比如创建 Collection 的装饰器,或实现迭代器。
二、使用 Guava 的好处
标准化:Guava库是由谷歌托管。
高效可靠:快速和有效的扩展JAVA标准库
优化:Guava 库经过高度的优化。
函数式编程:增加JAVA功能和处理能力。
实用程序:提供了经常需要在应用程序开发的许多实用程序类。
验证:提供标准的故障安全验证机制。
最佳实践:强调最佳的做法。
三、添加 Guava 库
Guava 库提供了两种不同的风格,比如 27.0.1-jre 或 27.0.1-android。
JRE 风格需要 JDK 1.8 或更高版本。
JDK 1.7 或 Android,请使用 Android 风格。可以在 android目录 中找到 Android Guava 源。
有关依赖于Guava的更多信息,请参阅 构建中使用Guava。
(1)Maven 添加依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>27.0.1-jre</version> </dependency>
(2)Gradle 添加依赖
compile group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'
注意: 此处我选择最新版本 27.0.1-jre
(3)源码包的简单说明:
com.google.common.annotations:普通注解类型。com.google.common.base:基本工具类库和接口。com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。com.google.common.eventbus:发布订阅风格的事件总线。com.google.common.hash: 哈希工具包。com.google.common.io:I/O工具包。com.google.common.math:原始算术类型和超大数的运算工具包。com.google.common.net:网络工具包。com.google.common.primitives:八种原始类型和无符号类型的静态工具包。com.google.common.reflect:反射工具包。com.google.common.util.concurrent:多线程工具包。
(4)Guava 目录结构
四、Optional 示例
所谓最佳实践,就是要强调最佳的行为做法,比如考虑到下面的代码片段。
public class GuavaTester {
public static void main(String args[]){
GuavaTester guavaTester = new GuavaTester();
Integer a = null;
Integer b = new Integer(10);
System.out.println(guavaTester.sum(a,b));
}
public Integer sum(Integer a, Integer b){
return a + b;
}
}运行程序,看到如下结果。
Exception in thread "main" java.lang.NullPointerException at com.example.test.GuavaTester.sum(GuavaTester.java:17) at com.example.test.GuavaTester.main(GuavaTester.java:13)
以上代码中存在如下问题。
sum()不采取任何的保护传递的参数为null。调用函数也并不担心传递一个
null到sum()方法而产生意外。当程序运行时
NullPointerException异常发生。
为了避免上述问题,null 检查需要每个这样存在问题地方。让我们来看看使用 Optional。Guava 提供实用工具类来标准化方式解决上述问题。引入 com.google.common.base.Optional 包。
import com.google.common.base.Optional;
public class GuavaTester {
public static void main(String args[]){
GuavaTester guavaTester = new GuavaTester();
Integer invalidInput = null;
Optional<Integer> a = Optional.of(invalidInput);
Optional<Integer> b = Optional.of(new Integer(10));
System.out.println(guavaTester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
return a.get() + b.get();
}
}运行程序,看到结果如下。
Exception in thread "main" java.lang.NullPointerException at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:877) at com.google.common.base.Optional.of(Optional.java:103) at com.example.test.GuavaTester.main(GuavaTester.java:9)
Java让我们来了解上述程序的一些重要概念。
Optional:实用类,使代码使用null能够正常。Optional.of:返回要用作参数Optional类的实例。检查传递的值是否为null。Optional.get:获取输入存储在Optional类的值。
使用 Optional 类,可以方便地查看调用者方法来传递参数正确与否。
Java 8 方式
目前 Guava 中的部分功能,在 Java8 中也有体现,比如,使用引用 java.util.Optional 包。
Exception in thread "main" java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at java.util.Optional.<init>(Optional.java:96) at java.util.Optional.of(Optional.java:108) at com.example.test.GuavaTester.main(GuavaTester.java:11)
五、Guava 快速示例
package com.example.guava;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.*;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.*;
public class GuavaTest {
/**
* 1、ImmutableList 只读集合
*/
@Test
public void testGuava1() {
// 1、使用 Arrays.asList 创建只读集合
// List<String> list = Arrays.asList("jack", "tom", "lily");
// list.add("vince");
// // 2、使用 Collections.unmodifiableList 创建只读集合
// List<String> list = new ArrayList<>();
// list.add("jack");
// list.add("tom");
// list.add("lily");
// List<String> readList = Collections.unmodifiableList(list);
// readList.add("vince");
// 3、使用 ImmutableList.of 创建只读集合
ImmutableList<String> list = ImmutableList.of("jack", "tom", "lily");
list.add("vince");
}
/**
* 2、函数式编程:过滤器
*/
@Test
public void testGuava2() {
// 使用 Lists.newArrayList 创建的集合非只读
ArrayList<String> list = Lists.newArrayList("java", "php", "javaScript", "h5", "jackson");
// 过滤输出以 j 开头的元素
Collection<String> result = Collections2.filter(list, (e) -> e.startsWith("j"));
result.forEach(System.out::println);
}
/**
* 3、函数式编程:转换
*/
@Test
public void testGuava3() {
Set<Long> timeSet = Sets.newHashSet(1520446283952L, 1580446283952L, 1542446287952L);
Collection<String> timeCollect = Collections2.transform(timeSet, (e) -> new SimpleDateFormat("yyyy-MM-dd").format(e));
timeCollect.forEach(System.out::println); // 2018-11-17、2018-03-08、2020-01-31
}
/**
* 4、组合式函数编程
*
* 1、如果元素长度大于4,截取
* 2、转换大写
* 3、转换集合
*/
@Test
public void testGuava4() {
ArrayList<String> list = Lists.newArrayList("java", "php", "javaScript", "h5", "jackson");
Function<String, String> f1 = (e) -> e.length() > 4 ? e.substring(0, 4) : e;
Function<String, String> f2 = (e) -> e.toUpperCase();
// 组合函数
Function<String, String> f = Functions.compose(f1, f2);
// 转换
Collection<String> strCollect = Collections2.transform(list, f);
strCollect.forEach(System.out::println);
}
/**
* 5、集合操作:交集、差集、并集
*/
@Test
public void testGuava5() {
Set<Integer> set1 = Sets.newHashSet(1, 2, 3);
Set<Integer> set2 = Sets.newHashSet(3, 4, 5);
System.out.println("-------- 交集 ------");
// 交集
Sets.SetView<Integer> v1 = Sets.intersection(set1, set2);
v1.forEach(System.out::println);
System.out.println("\n-------- 差集 ------");
// 差集
Sets.SetView<Integer> v2 = Sets.difference(set1, set2);
v2.forEach(System.out::println);
System.out.println("\n-------- 并集 ------");
// 并集
Sets.SetView<Integer> v3 = Sets.union(set1, set2);
v3.forEach(System.out::println);
}
/**
* 6、Multiset:无序可重复
*/
@Test
public void testGuava6() {
String str = "good good study day day up";
String[] ss = str.split(" ");
HashMultiset<String> multiset = HashMultiset.create();
for (String s : ss) {
multiset.add(s);
}
Set<String> set = multiset.elementSet();
// 查看相同元素的个数
set.forEach(s -> System.out.println(s + " : " + multiset.count(s)));
}
/**
* 7、Multimap key 可以重复
*
* 将相同的key合并,value值为list
*/
@Test
public void testGuava7() {
Map<String, String> map = new HashMap<>();
map.put("Java 从入门到精通", "bin");
map.put("Android 从入门到精通", "bin");
map.put("PHP 从入门到精通", "jack");
map.put("笑看人生", "vince");
// 创建 ArrayListMultimap 将 map 的key,value 反向存储
ArrayListMultimap<String, String> listMultimap = ArrayListMultimap.create();
map.forEach((k, v) -> listMultimap.put(v, k));
System.out.println(listMultimap);
System.out.println("\n------ 遍历 ArrayListMultimap -----");
// 遍历,能看出来有两个 key 为 bin
listMultimap.forEach((k, v) -> System.out.println(k + " : " + v));
System.out.println("\n------ 遍历 keySet -----");
listMultimap.keySet().forEach(k -> {
List<String> values = listMultimap.get(k);
System.out.println(k + " : " + values);
});
}
/**
* 8、BiMap:双向 Map (bidirectional Map)键与值不能重复
*/
@Test
public void testGuava8() {
// 使用场景,比如微信号和手机号绑定
BiMap<String, String> biMap = HashBiMap.create();
biMap.put("tingfeng", "13000000000");
biMap.put("renkui", "18000000000");
biMap.put("xiaomiao", "15000000000");
// 使用 inverse 将 key,value 反转
String username = biMap.inverse().get("13000000000");
System.out.println("账号:" + username);
}
/**
* 9、双键的 Map --> Table --> rowKey+columnKye+value
*/
@Test
public void test1() {
Table<Object, Object, Object> table = HashBasedTable.create();
table.put("jack", "java", 98);
table.put("jack", "php", 65);
table.put("jack", "ui", 80);
table.put("jack", "mysql", 86);
// 遍历
Set<Table.Cell<Object, Object, Object>> cells = table.cellSet();
cells.forEach(c -> System.out.println(c.getRowKey() + "-" + c.getColumnKey() + " : " + c.getValue()));
}
}六、相关文章
未经允许请勿转载:程序喵 » Google Guava 快速入门 —— Guava介绍
程序喵