Google Guava 工具集
Guava 工程包含了若干被 Google 的 Java 项目广泛依赖的核心库
使用和避免 null
大多数情况下,使用 null 表明的是某种缺失情况
Guava 引入 Optional 表示可能为 null 的 T 类型引用。Optional 实例可能包含非 Null 的引用(引用存在),也可能什么也不包括(引用缺失)
正是受到 Guava 的启发, Java 8 将 Optional 类做为一个新特性引入进 Java 8 的类库
Java8 新特性 Optional
三种创建 Optional 对象方式
// 1.创建空的 Optional 对象
Optional.empty();
// 2.使用非 null 值创建 Optional 对象
Optional.of("Hello");
// 3.使用任意值创建 Optional 对象
Optional.ofNullable(null);
Optional<Object> optional = Optional.ofNullable("Hello World");
// 判断是否引用缺失的方法(建议不直接使用,与以往的判断非 null 无区别)
optional.isPresent();
// 当 optional 引用存在时执行
// 类似的方法:map filter flatMap
optional.ifPresent(System.out::println); // Hello World
// 当 optional 引用缺失时执行
optional.orElse("引用缺失");
optional.orElseGet(() -> {
// 自定义引用缺失时的返回值
return "自定义引用缺失";
});
optional.orElseThrow(() -> {
throw new RuntimeException("引用缺失异常");
});
不可变集合
创建对象的不可变拷贝是一项很好的防御性编程技巧
Guava 为所有 JDK 标准集合类型和 Guava 新集合类型都提供了简单易用的不可变版本
不可变对象的优点:
-
当对象被不可信的库调用时,不可变形式是安全的
-
不可变对象被多个线程调用时,不存在竞态条件问题
-
不可变集合不需要考虑变化,因此可以节省时间和空间
-
不可变对象因为固定不变,可以作为常量来安全使用
JDK 提供的 unmodifiableXXX 方法:
-
笨重且累赘
-
不pvwg
-
低效
package escape.guava;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ImmutableTest {
public static void test(List<Integer> list) {
list.remove(0);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<Integer> newList = Collections.unmodifiableList(list);
test(newList);
System.out.println(newList);
}
}
现在集合是不可变的,在修改时就会抛异常
但是这样过于繁琐
Guava 为我们提供了三种创建不可变集合的方式:
- copyOf
ImmutableSet.copyOf(set)
- of
ImmutableSet.of("a", "b", "c")
- Builder
ImmutableSet.builder().build()
引入 guava
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
public void immutable() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
// 通过已存在的集合创建
ImmutableSet<Integer> im1 = ImmutableSet.copyOf(list);
// 通过初始化值,直接创建不可变集合
ImmutableSet<Integer> im2 = ImmutableSet.of(1, 2, 3);
// 以 builder 方式创建
ImmutableSet<Object> im3 = ImmutableSet.builder()
.add(1)
.addAll(Sets.newHashSet(2, 3))
.add(4)
.build();
}
新集合类型
Guava 引入了很多 JDK 没有的、但明显有用的新集合类型。这些新类型是为了和 JDK 集合框架共存,而没有往 JDK 集合抽象中硬塞其他概念
Multiset
结合了 set 和 list 的特点:无序,元素可重复
实例:使用 Multiset 集合类,实现统计一篇文章中文字出现次数功能
package escape.guava;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import com.google.common.primitives.Chars;
import org.junit.Test;
public class MultisetTest {
private static final String text =
"《南陵别儿童入京》" +
"白酒新熟山中归,黄鸡啄黍秋正肥。" +
"呼童烹鸡酌白酒,儿女嬉笑牵人衣。" +
"高歌取醉欲自慰,起舞落日争光辉。" +
"游说万乘苦不早,著鞭跨马涉远道。" +
"会稽愚妇轻买臣,余亦辞家西入秦。" +
"仰天大笑出门去,我辈岂是蓬蒿人。";
@Test
public void handle() {
Multiset<Character> multiset = HashMultiset.create();
// string 转换成 char 数组
char[] chars = text.toCharArray();
Chars.asList(chars)
.forEach(charItem -> {
multiset.add(charItem);
});
System.out.println("size: " + multiset.size());
System.out.println("count: " + multiset.count('人'));
}
}
结果:
size: 105
count: 2
集合工具类
Guava 为集合类提供了许多工具方法,这也是 Guava 最流行和成熟的部分之一
常见的集合工具类如:Lists, Sets, Maps 等
package escape.guava;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.experimental.var;
import org.junit.Test;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class SetsTest {
// Sets 工具类的常用方法
private static final Set<Integer> set1 = Sets.newHashSet(1, 2, 3, 4);
private static final Set<Integer> set2 = Sets.newHashSet(4, 5, 6);
// 并集
@Test
public void union() {
Sets.SetView<Integer> set = Sets.union(set1, set2);
System.out.println(set);
}
// 交集
@Test
public void intersection() {
Sets.SetView<Integer> intersection = Sets.intersection(set1, set2);
System.out.println(intersection);
}
// 差集与相对差集
@Test
public void difference() {
// 差集: 如果元素属于A而且不属于B
Sets.SetView<Integer> set = Sets.difference(set1, set2);
System.out.println(set);
// 相对差集:属于A且不属于B 或 属于B且不属于A
Sets.SetView<Integer> integers = Sets.symmetricDifference(set1, set2);
System.out.println(integers);
}
// 拆分所有子集合
@Test
public void powerSet() {
Set<Set<Integer>> sets = Sets.powerSet(set1);
System.out.println(sets);
System.out.println(JSON.toJSONString(sets, true));
}
// 计算笛卡尔积
@Test
public void cartesianProduct() {
Set<List<Integer>> lists = Sets.cartesianProduct(set1, set2);
System.out.println(lists);
}
// 分组
@Test
public void partition() {
ArrayList<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
// 拆分成每三个值一组
List<List<Integer>> partition = Lists.partition(list, 3);
System.out.println(partition);
}
// 反转集合
@Test
public void reverse() {
LinkedList<Integer> list = Lists.newLinkedList();
list.add(1);
list.add(2);
list.add(3);
List<Integer> reverse = Lists.reverse(list);
System.out.println(reverse);
}
}
IO 流工具集
ByteStreams: 提供对 InputStream/OutputStream 的操作
CharStreams: 提供对 Reader/Writer 的操作
对源(Source)与汇(Sink)的抽象
源是可读的:ByteSource/CharSource
汇是可写的:ByteSink/CharSink
实例:拷贝文件
package escape.guava;
import com.google.common.base.Charsets;
import com.google.common.io.CharSink;
import com.google.common.io.CharSource;
import com.google.common.io.Files;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
public class IOTest {
@Test
public void copyFile() throws IOException {
// 会自动关闭资源
// 创建对应的 Source 和 Sink
CharSource charSource = Files.asCharSource(new File("pom.xml"), Charsets.UTF_8);
CharSink charSink = Files.asCharSink(new File("target_pom.xml"), Charsets.UTF_8);
// 拷贝
charSource.copyTo(charSink);
}
}
极其简单,而且也不会手动关闭资源
- 上一篇: Stream 实战案例
- 下一篇: 验证框架
