Google Guava 工具类的介绍和使用

 2023-02-05
原文作者:蒋先森 原文地址:https://jlj98.top/

概述

工具类就是封装平时常用的方法,不需要重复造轮子,今天介绍下谷歌的 guava。

guava 的优点:

  • 高效设计良好的API,被 Google 的开发者设计,实现和使用
  • 遵循高效的Java的语法实践
  • 使代码更刻度,简洁,简单
  • 节约时间,资源,提高生产力

Guava 工具包包含若干个 Google Java项目:

  • 集合
  • 缓存
  • 原生类型支持
  • 并发库
  • 通用注解
  • 字符串处理
  • I/O 等

在使用时,只需要在项目依赖中加入 Google Guava:

    <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>31.0.1-jre</version>
    </dependency>

集合

Google Guava 工具包提供了大量创建和使用集合的方法。

    public static void main(String[] args) {
        // 普通 Collection 创建
        List<String> list = Lists.newArrayList();
        Set<String> set = Sets.newHashSet();
        Map<String, String> map = Maps.newHashMap();
        // BiMap: 双向Map(Bidirectional Map)键和值不能重复
        BiMap<String, String> biMap = HashBiMap.create();
    
        // 不可变 Collection创建
        ImmutableList<String> iList = ImmutableList.of("a", "b", "c");
        ImmutableSet<String> iSet = ImmutableSet.of("a", "b", "c");
        ImmutableMap<String, String> iMap = ImmutableMap.of("k1", "v1", "k2", "v2");
    }

集合和特定字符串转换

    public static void main(String[] args) {
        // 普通 Collection 创建
        List<String> list = Lists.newArrayList();
        Set<String> set = Sets.newHashSet();
        Map<String, String> map = Maps.newHashMap();
    
        // 不可变 Collection创建
        ImmutableList<String> iList = ImmutableList.of("a", "b", "c");
        ImmutableSet<String> iSet = ImmutableSet.of("a", "b", "c");
        ImmutableMap<String, String> iMap = ImmutableMap.of("k1", "v1", "k2", "v2");
    
        // BiMap: 双向Map(Bidirectional Map)键和值不能重复
        BiMap<String, Integer> biMap = HashBiMap.create();
        biMap.put("张三",54);
        biMap.put("李四",23);
        biMap.put("程思",33);
        biMap.put("吴楠",16);
    
        //key相同value不同,后面的会覆盖前面的
        biMap.put("吴楠",46);
        //启动程序会报错 java.lang.IllegalArgumentException: value already present: 23
        //biMap.put("张刚",23);
        //强行添加,会覆盖
        //biMap.forcePut("张刚",23);
        System.out.println(biMap);
        //反转 key和value反转
        BiMap<Object, Object> inverseMap = biMap.inverse();
        System.out.println(inverseMap);
    }

将集合转换成特定字符串,很多工具都支持这个功能。

集合切割(Lists.partitions)

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        int num = 20;
        for (int i = 0; i < num; i++) {
            list.add(i);
        }
        System.out.println(Lists.partition(list, 5));
    }

输出:

    [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]

其他功能

    public static void main(String[] args) {
        //反转list
        List<String> reverseList1 = Lists.reverse(list);
        System.out.println("反转:" + reverseList1);
    
        // 集合过滤 [guava, Java]
        ImmutableList<String> names = ImmutableList.of("code", "guava", "google", "alibaba", "Java", "Go");
        Iterable<String> filterList = Iterables.filter(names, Predicates.or(
                Predicates.equalTo("guava"), Predicates.equalTo("Java")));
        System.out.println(filterList);
    
        // 自定义过滤条件: {a=12, b=15}
        ImmutableMap<String, Integer> m = ImmutableMap.of("a", 12, "b", 15);
        // Function<F, T> 中 F表示apply()方法input的类型,T表示apply()返回的类型
        Map<String, Integer> m2 = Maps.transformValues(m, new Function<Integer, Integer>() {
            @Override
            public @Nullable Integer apply(@Nullable Integer input) {
                if (input > 12) {
                    return input;
                } else {
                    return input++;
                }
            }
        });
        System.out.println(m);
    
        // 交集、并集、差集
        Set<String> set1 = Sets.newHashSet("a", "b", "c");
        Set<String> set2 = Sets.newHashSet("a", "c", "d");
        // 并集
        Sets.SetView<String> union = Sets.union(set1, set2);
        System.out.println("并集:" + union);
        // 差集
        Sets.SetView<String> difference = Sets.difference(set1, set2);
        System.out.println("差集" + difference);
        // 交集
        Sets.SetView<String> intersection = Sets.intersection(set1, set2);
        System.out.println("交集:" + intersection);
    }

也支持很多Map的操作,现在列举一些基础使用方法:

    public static void main(String[] args) {
        /**Map的常见用法*/
        Map<String, Object> leftMap = ImmutableMap.of("name", "汪", "age", 18, "address", "陕西", "city", "西安", "love", "张");
        Map<String, Object> rightMap = ImmutableMap.of("name", "张", "age", 16, "address", "陕西", "city", "西安", "home", "美国");
        MapDifference<String, Object> deffMap = Maps.difference(leftMap, rightMap);
        //相同的
        Map<String, Object> map = deffMap.entriesInCommon();
        System.out.println("相同的:" + map);
        //同key不同value
        Map<String, MapDifference.ValueDifference<Object>> stringValueDifferenceMap = deffMap.entriesDiffering();
        System.out.println("同key不同value:" + stringValueDifferenceMap);
        //仅仅左边有的
        Map<String, Object> onlyLeft = deffMap.entriesOnlyOnLeft();
        System.out.println("仅仅左边有的:" + onlyLeft);
        //仅仅右边有的
        Map<String, Object> onlyRight = deffMap.entriesOnlyOnRight();
        System.out.println("仅仅右边有的:" + onlyRight);
    }

字符串处理

    public static void main(String[] args) {
        // 去除空格: [1, 2, 3, 4, 5, 6]
        String str = "1-2-3-4-  5-   6     ";
        List<String> trimList = Splitter.on("-")
                .omitEmptyStrings()
                // 可指定字符
                .trimResults()
                .splitToList(str);
        System.out.println(trimList);
    
        // String -> Map
        String mapStr = "zhangsan=25,lisi=90";
        Map<String, String> splitMap = Splitter.on(",")
                .withKeyValueSeparator("=")
                .split(mapStr);
        System.out.println(splitMap);
    
        // guava 支持多字符或者正则切分:[aa, dd, ff]
        String input = "aa.dd,,ff,,.";
        List<String> result = Splitter.onPattern("[.|,]")
                .omitEmptyStrings()
                .splitToList(input);
        System.out.println(result);
    
        System.out.println("==========CharMatcher===============");
        // 匹配所有的
        CharMatcher charMatcher1 = CharMatcher.any();
        CharMatcher charMatcher2 = CharMatcher.anyOf("aef");
        // 什么也不匹配的
        CharMatcher charMatcher3 = CharMatcher.none();
        // 匹配空白字符的
        CharMatcher charMatcher4 = CharMatcher.whitespace();
        CharMatcher charMatcher4_1 = CharMatcher.breakingWhitespace();
        // 匹配单个字符
        CharMatcher charMatcher5 = CharMatcher.is('a');
        CharMatcher charMatcher6 = CharMatcher.isNot('a');
        // 匹配范围
        CharMatcher charMatcher7 = CharMatcher.inRange('0', '9');
        CharMatcher charMatcher8 = CharMatcher.inRange('a', 'z');
        CharMatcher charMatcher9 = CharMatcher.inRange('A', 'Z');
        
        System.out.println("==========CaseFormat===============");
        // 转驼峰:constantName
        String lowerCamel = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME");
        System.out.println(lowerCamel);
        // 转驼峰:ConstantName
        String upperCamel = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "CONSTANT_NAME");
        System.out.println(upperCamel);
        // 转小写:constant-name
        String lowerHyphen = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, "CONSTANT_NAME");
        System.out.println(lowerHyphen);
        // 转小写:constant_name
        String lowerUnderscore = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_UNDERSCORE, "CONSTANT_NAME");
        System.out.println(lowerUnderscore);
        // CONSTANT_NAME
        String upperUnderscore = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, "CONSTANT_NAME");
        System.out.println(upperUnderscore);
    }

并发库

ThreadFactoryBuilder

SettableFuture

ListenableFuture

Guava 定义了 ListenableFuture 接口并继承了JDK concurrent包下的Future 接口,扩展了一个addListener 监听方法,当任务执行完成,会主动回调该方法。主要也是弥补了JDK自带Future的不足,像Netty 也优雅的实现了异步回调机制,不需要手动通过 Future.get() 来获取结果。

Futures.addCallback

AsyncFunction

缓存

Guava Cache 可以作为本地缓存,支持很多方式

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //google guava cache CacheBuilder的构造函数是私有的,在智能通过静态方法 newBuilder 来获取 CacheBuilder 实例
        LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
                //设置并发级别为8,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒过期
                .expireAfterWrite(8, TimeUnit.SECONDS)
                //设置初始容量 10
                .initialCapacity(10)
                //设置缓存最大容量为100,超过100之后就会按照 LRU 最近最少使用算法来移除缓存
                .maximumSize(100)
                //定时刷新数据
                .refreshAfterWrite(1, TimeUnit.SECONDS)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存移除通知
                .removalListener(new RemovalListener<Object, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<Object, Object> notification) {
                        System.out.println(notification.getKey() + " was removed, cause is" + notification.getCause());
                    }
                })
                .build(
                        //build 方法可以指定CacheLoader,在缓存不存在是通过CacheLoader的实现自动加载缓存
                        new CacheLoader<Integer, String>() {
                            @Override
                            public String load(Integer key) throws Exception {
                                System.out.println("load data: " + key);
                                String str = key + ":cache-value";
                                return str;
                            }
                        }
                );
        for (int i = 0; i < 20; i++) {
            String str = cache.get(1);
            System.out.println(str);
            //休眠一秒
            TimeUnit.SECONDS.sleep(1);
        }
    
        System.out.println("cache status:");
    
        System.out.println(cache.stats().toString());
    }

文件I/O

    public static void main(String[] args) {
        File file = new File("D:\\Document\\temp\\test.txt");
        List<String> list = null;
        try {
            list = Files.readLines(file, Charsets.UTF_8);
        }catch (Exception e){
        }
        // 文件拷贝
        Files.copy(form, to);
        Files.move(File from, File to);
    }