当前位置 > it书童 > java > 正文

Google Guava 工具集

java it书童 2021-01-14 16:37:09 0赞 0踩 176阅读 0评论

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);
    }
}

极其简单,而且也不会手动关闭资源

关于我
一个文科出身的程序员,追求做个有趣的人,传播有价值的知识,微信公众号主要分享读书思考心得,不会有代码类文章,非程序员的同学请放心订阅
转载须注明出处:https://www.itshutong.com/articles/1029