一、什么是 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介绍