文章目录
Guava的类特别多,就将常用的进行展开记录,以后需要用到了再补充
Guava简介
Guava工程包含了若干个被Google的Java项目广泛依赖的核心库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/0等等
引入依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
对null处理 :Optional类
Optional 类是一个可以为null的容器对象
Optional 类的引入很好的解决空指针异常
JDK8中,将Optional类引入到了Java 8的类库,所以可以直接使用JDK的Optional类
创建Optional对象的三种方式
//创建空的Optional对象
Optional.empty();
//使用非null值创建Optional对象
Optional.of("zhangsan");
//使用任意值创建Optional对象
Optional<Object> optional = Optional.ofNullable("zhangsan");
常用方法:
- 判断是否引用缺失(null)
/**
* 判断是否引用缺失(是否为空)
* 不建议使用
*/
optional.isPresent();
- 如果引用存在(非nulll),则进行系列操作
/**
* 如果引用存在,即不为null,进行操作(如打印)
* 类似的有map。flatmap,filter
*/
optional.ifPresent(System.out::println);
- 引用缺失时的三种操作
optional.orElse("引用缺失");//缺失修改值为某值
optional.orElseGet(() -> {//缺失时直接进行相应操作(如返回提示)
return "自定义引用缺失";
});
optional.orElseThrow(() -> {//缺失时可以抛出异常
throw new RuntimeException("引用缺失异常");
});
- 实际应用实践
创建一个方法通过流打印集合内容
public static void stream(List<String> list) {
//如果list为空,会抛出异常
list.stream().forEach(System.out::println);
}
如果list为空,则会抛出异常,stream初始化失败
使用Optional进行优化:
public static void stream(List<String> list) {
//如果list不为空,初始化流,如果为空,初始化一个空的流
Optional.ofNullable(list)
.map(List::stream)
.orElseGet(Stream::empty)
.forEach(System.out::println);
}
- 首先通过 Optional.ofNullable(list)创建一个Optional对象
- 如果Optional对象引用存在,则执行map中的list.stream()方法
- 如果Optional对象引用缺失,则执行 Stream.empty()方法创建一个空的对象
- 最后再打印输出
不可变集合 :Immutable*类
不可变对象的优点:
- 当对象被不可信的库调用时,是安全的
- 不可变对象在多线程环境下安全
- 不可变集合不需要考虑变化,可以节省时间和空间
- 不可变对象常作为常量来安全使用
Immutabl*是一系列的不可变集合,包括了很多很多的类,使用起来其实大同小异,一下就以ImmutableSet说明下他的创建
创建不可变对象的三种方式(以ImmutableSet为例)
List<Integer>list = new ArrayList<Integer>(){
{add(1);}
{add(2);}
{add(3);}
};
//通过已存在集合创建
ImmutableSet.copyOf(list);
//通过初始值直接创建不可变集合
ImmutableSet.of(1, 2, 3, 4, 5);
//以builder方式创建
ImmutableSet immutableSet = ImmutableSet.builder()
.add(1)
.addAll(Sets.newHashSet(2, 3, 4))
.add(5)
.build();
构建好的Immutable*的对象不具有添加和删除的接口
新的集合类型 Multiset接口
类似的还有和Multimap接口,一下以Multiset为例
Multiset是一种介于Set和List直接的一种数据结构,两种角度理解Multiset
- 没有元素顺序限制的ArrayList
- add(E):添加单个元素
- iterator():返回一个迭代器
- size():返回所有元素的总个数(包括重复的)
- Map<E,Integer>,键为元素,值为计数
- count(Object):返回给的元素的计数
- entrySet():相当于Map中的entrySet
- elementSet():相当于Map中的KeySet
接口的五种实现类:
- HashMultiset
- TreeMultiset
- LinkedHashSet
- ConcurrentHashMultiset
- mmutableMultiset
业务中的实践:
实现字符统计的功能
/**
* 〈使用Mutiset统计古诗文字出现频率〉
*
* @author Chkl
* @create 2020/4/21
* @since 1.0.0
*/
public class MultisetTest {
private static final String text =
"《山坡羊·潼关怀古》\n" +
"峰峦如聚,波涛如怒,山河表里潼关路。 \n" +
"望西都,意踌躇。\n" +
"伤心秦汉经行处,宫阙万间都做了土。 \n" +
"兴,百姓苦。亡,百姓苦。";
@Test
public void handle(){
//创建Multiset
Multiset<Character> multiset = HashMultiset.create();
//stirng to char
char[] chars = text.toCharArray();
//遍历数组,加入到multiset
Chars.asList(chars)
.stream()
.forEach(charitem->{
multiset.add(charitem);
});
System.out.println(multiset.size());
for (Character c : multiset.elementSet()){
System.out.println(c+" "+multiset.count(c));
}
}
}
常用工具集 :Sets、Lists类
Sets工具类常用方法: 并集、交集、差集、分解集合中所有的子集、求两个集合的笛卡尔积
Lists工具类常用方法: 反转、拆分
演示实践:
初始化两个set
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);
}
- 求差集
元素属于a但不属于b
@Test
public void difference() {
Set<Integer> set = Sets.difference(set1, set2);
System.out.println(set);
}
- 求相对差集
元素属于a但不属于b 或元素属于b但不属于a
@Test
public void symmetricDifference() {
Set<Integer> set = Sets.symmetricDifference(set1, set2);
System.out.println(set);
}
- 拆解集合(求所有子集)
@Test
public void powerSet() {
Set<Set<Integer>> set = Sets.powerSet(set1);
System.out.println(JSON.toJSONString(set));
}
- 求笛卡尔积
@Test
public void cartesianProduct() {
Set<List<Integer>> set = Sets.cartesianProduct(set1, set2);
System.out.println(JSON.toJSONString(set));
}
初始化一个List
private static final List<Integer> list =
Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
- 按指定长度拆分
@Test
public void partition() {
List<List<Integer>> partition = Lists.partition(list, 3);
System.out.println(JSON.toJSONString(partition));
}
- 反转集合
@Test
public void reverse() {
List<Integer> reverse = Lists.reverse(list);
System.out.println(JSON.toJSONString(reverse));
}
IO操作: Files类
对字节流和字符流操作的封装
- ByteStreams:提供对InputStream和OutputStream针对字节流的操作
- CharStreams:提供Reader和Writer针对字符流的操作
针对源(Source)和汇(Sink)的抽象
- 源(可读的):ByteSource/CharSource
- 汇(可写的):ByteSink/CharSink
Files中封装了很多好用的方法,这里主要记录一下源与汇的使用
实践案例:
通过源与汇实现文件拷贝,源与汇是比较高级的封装,直接使用不需要对输入输出流进行创建和关闭
/**
* 通过源与汇实现文件拷贝
*/
@Test
public void copyFile() throws IOException {
/**
* 创建对应的Source和Sink
*/
CharSource charSource = Files.asCharSource(
new File("lib/FileCopy.java"), Charsets.UTF_8);
CharSink charSink = Files.asCharSink(
new File("outTest/out.txt"), Charsets.UTF_8);
/**
* 拷贝,不需要创建连接和关闭连接
*/
charSource.copyTo(charSink);
}
更多的方法在具体使用时查Api吧 ,源与汇还是挺好用的
最后
Guava用起来非常强大,方法也非常多,找到一个算是目录的网站,可以去系统的看一看Api 直达