Google Guava 工具集简介
Guava工程包含了若干被Google的Java项目广泛依赖的核心库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O等等。
所有这些工具每天都在被Google的工程师应用在产品服务中。
使用和避免null
大多数情况下,使用null表明的是某种缺失
情况。
Guava引入Optionl
实例
/**
* @author fangliu
* @date 2020-02-15
* @description 学习Java8中的optional使用方法
*/
public class OptionalTest {
@Test
public void test() throws Throwable {
/**
* 三种创建Optional
*/
// 创建空的Optional对象
Optional.empty();
// 使用非null值创建Optional对象
Optional.of("Optional");
// 使用任意值创建Optional对象
Optional optional = Optional.ofNullable(null);
/**
* 判断是否引用缺失的方法(建议不直接使用)
*/
optional.isPresent();
/**
* optional引用存在时执行
* 类似的方法:map filter flatMap
*/
optional.ifPresent(System.out::println);
/**
* 当optional引用缺失时执行
* orElse():如果有值则将其返回,否则返回指定的其它值。
* orElseGet():如果有值则将其返回,否则调用函数并将其返回调用结果。
* 由于orElseGet()不是每次都会调用传入的方法,所以orElseGet()方法在性能上要优于orElse()方法。
*/
optional.orElse(get("引用缺失"));
optional.orElseGet(()->{
// 自定义引用缺失时的返回值
System.out.println("自定义引用缺失");
return "自定义引用缺失";
});
optional.orElseThrow(()->{
throw new RuntimeException("引用缺失异常");
});
}
public static int get(String name) {
System.out.println(name);
return 1;
}
}
不可变对象的优点
- 当对象被不可信的库调用时,不可变形式是安全的
- 不可变对象被多个线程调用时,不存在竞态条件问题
- 不可变集合不需要考虑变化,因此可以节省时间和空间
- 不可变对象因为有固定不变,可以作为常量来安全使用
JDK提供的unmodifiableXXX方法
- 笨重而且累赘
- 不安全
- 低效
实例
/**
* @author fangliu
* @date 2020-02-16
* @description 不可变集合用法
*/
public class ImmutableTest {
public static void test(List<Integer> list){
list.remove(0);
}
@Test
public void test(){
List<Integer> list= new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
// 通过Collections的unmodifiableList方法让list不可变
List<Integer> newList = Collections.unmodifiableList(list);
test(newList);
System.out.println(list);
}
}
Guava提供的不可变集合的三种创建方式
- copyOf方法:ImmutableSet.copyOf(set)
- of方法:ImmutableSet.of("a","b","c")
- Builder工具:ImmutableSet.builder().build()
public void immutable(){
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
/**
* 构造不可变集合对象三种方式
*/
// 通过已经存在的集合创建
ImmutableSet.copyOf(list);
// 通过初始值,直接创建不可变集合
ImmutableSet immutableSet = ImmutableSet.of(1,2,3,4,5);
//以builder方式创建
ImmutableSet.builder()
.add(1)
.addAll(Sets.newHashSet(2,3,4))
.add(5)
.build();
}
新集合类型
Guava引入了很多JDK没有的,但明显有用的新集合类型。这些类型是为了和JDK集合框架共存,而没有往JDK集合抽象中硬塞其他概念
Set 无序不可重复集合
List 有序可重复集合
Multiset 无序可重复集合
实例
/**
* @author fangliu
* @date 2020-02-16
* @description 使用Multiset统计一首古诗的文字出现频率
*/
public class MultisetTest {
private static final String text =
"择一城终老,遇一人白首。挽一帘幽梦,许一世倾城。写一字决别,言一梦长眠。我倾尽一生,囚你无期。 " +
"择一人深爱,等一人终老。痴一人情深,留一世繁华。断一根琴弦,歌一曲离别。我背弃一切,共度朝夕。";
private static final String text1 =
"三生有幸遇见你 纵使悲凉也是情;" +
"一世无缘却相逢,即便欣喜也无果!";
@Test
public void handle (){
// multiset创建
Multiset<Character> multiset = HashMultiset.create();
// string 转化成char数组
char[] chars = text.toCharArray();
// 遍历数组,添加到multiset中
Chars.asList(chars)
.stream()
.forEach(charItem->multiset.add(charItem));
System.out.println("size:"+multiset.size());
System.out.println("count:"+multiset.count('人'));
}
}
集合工具类
Guava为集合类提供了许多工具方法。这也是Guava最流行和成熟的部分之一
常见的集合工具类如:Lists,Sets,Maps等。
实例
/**
* @author fangliu
* @date 2020-02-16
* @description Guava集合使用
*/
public class CollectionsTest {
/**
* Sets工具类的常用方法
* 并集/交集/差集/分解集合中的所有子集/求两个集合的笛卡尔积
* <p>
* Lists工具类的常用方式
* 反转/拆分
*/
private static final Set set1 = Sets.newHashSet(1, 2, 3, 4);
private static final Set set2 = Sets.newHashSet(4, 5, 6);
// 并集
@Test
public void union() {
Set<Integer> set = Sets.union(set1, set2);
System.out.println(set);
}
// 交集
@Test
public void intersection() {
Set<Integer> set = Sets.intersection(set1, set2);
System.out.println(set);
}
// 差集
@Test
public void difference() {
// 属于set1并且不属于set2
Set<Integer> set = Sets.difference(set1, set2);
System.out.println(set);
// 相对差集:set1、set2差集之外的值
set = Sets.symmetricDifference(set1, set2);
System.out.println(set);
}
// 分解集合中的所有子集
@Test
public void powerSet() {
// 属于set1并且不属于set2
Set<Set<Integer>> set = Sets.powerSet(set1);
System.out.println(JSON.toJSONString(set));
}
// 求两个集合的笛卡尔积
@Test
public void cartesianProduct() {
// 属于set1并且不属于set2
Set<List<Integer>> set = Sets.cartesianProduct(set1, set2);
System.out.println(JSON.toJSONString(set));
}
// 拆分
@Test
public void partition() {
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
// 几个为一组拆分
List<List<Integer>> partition = Lists.partition(list, 2);
System.out.println(JSON.toJSONString(partition));
}
// 反转
@Test
public void reverse() {
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
List<Integer> reverse = Lists.reverse(list);
System.out.println(JSON.toJSONString(reverse));
}
}
IO综述
- ByteStreams:提供对InputStream/OutputStream的操作
- CharStreams:提供对Reader/Writer的操作
源(Source)与汇(Sink)的抽象
- 源是可读的:ByteSource/CharSource
- 汇是可写的:ByteSink/CharSink
实例
/**
* @author fangliu
* @date 2020-02-16
* @description 源(Source)与汇(Sink)对文件进行常用操作
*/
public class IOTest {
@Test
public void copyFile() throws IOException {
/**
* 创建对应的Source和Sink
*/
CharSource charSource = Files.asCharSource(
new File("SourceText.txt"), Charsets.UTF_8);
CharSink charSink = Files.asCharSink(
new File("TargetText.txt"),Charsets.UTF_8
);
/**
* 拷贝
*/
charSource.copyTo(charSink);
}
}