Google Guava 快速入门 —— Guava介绍

Google Guava 快速入门.jpg

一、什么是 Guava

Guava 工程包含了若干被 Google 的 Java 项目广泛依赖的核心库,例如:集合【collections】、缓存【caching】、原生类型支持【primitives support】、并发库【concurrency libraries】、通用注解【common annotations】、字符串处理【string processing】、I/O 和 验证等等。所有这些工具每天都在被 Google 的工程师应用在产品服务中。

Guava 对 JDK 集合的扩展,这是 Guava 最成熟和为人所知的部分。

  • 1、不可变集合:用不变的集合进行防御性编程和性能提升。

  • 2、新集合类型:multisets, multimaps, tables,等。

  • 3、强大的集合工具类:提供 java. Util. Collections 中没有的集合工具。

  • 4、扩展工具类:让实现和扩展集合类变得更容易,比如创建 Collection 的装饰器,或实现迭代器。

二、使用 Guava 的好处

  • 标准化:Guava库是由谷歌托管。

  • 高效可靠:快速和有效的扩展JAVA标准库

  • 优化:Guava 库经过高度的优化。

  • 函数式编程:增加JAVA功能和处理能力。

  • 实用程序:提供了经常需要在应用程序开发的许多实用程序类。

  • 验证:提供标准的故障安全验证机制。

  • 最佳实践:强调最佳的做法。

三、添加 Guava 库

Guava 库提供了两种不同的风格,比如 27.0.1-jre 或 27.0.1-android

  • JRE 风格需要 JDK 1.8 或更高版本。

  • JDK 1.7 或 Android,请使用 Android 风格。可以在 android目录 中找到 Android Guava 源。

有关依赖于Guava的更多信息,请参阅 构建中使用Guava

(1)Maven 添加依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.0.1-jre</version>
</dependency>

(2)Gradle 添加依赖

compile group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'

注意: 此处我选择最新版本 27.0.1-jre

(3)源码包的简单说明:

  • com.google.common.annotations:普通注解类型。

  • com.google.common.base:基本工具类库和接口。

  • com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。

  • com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。

  • com.google.common.eventbus:发布订阅风格的事件总线。

  • com.google.common.hash: 哈希工具包。

  • com.google.common.io:I/O工具包。

  • com.google.common.math:原始算术类型和超大数的运算工具包。

  • com.google.common.net:网络工具包。

  • com.google.common.primitives:八种原始类型和无符号类型的静态工具包。

  • com.google.common.reflect:反射工具包。

  • com.google.common.util.concurrent:多线程工具包。

(4)Guava 目录结构

guava-directory_structure.jpg

四、Optional 示例

所谓最佳实践,就是要强调最佳的行为做法,比如考虑到下面的代码片段。

public class GuavaTester {
   public static void main(String args[]){
      GuavaTester guavaTester = new GuavaTester();
      
      Integer a =  null;
      Integer b =  new Integer(10);
      System.out.println(guavaTester.sum(a,b));
   }
   
   public Integer sum(Integer a, Integer b){
      return a + b;
   }    
}

运行程序,看到如下结果。

Exception in thread "main" java.lang.NullPointerException
    at com.example.test.GuavaTester.sum(GuavaTester.java:17)
    at com.example.test.GuavaTester.main(GuavaTester.java:13)

以上代码中存在如下问题。

  • sum() 不采取任何的保护传递的参数为 null

  • 调用函数也并不担心传递一个 null 到 sum() 方法而产生意外。

  • 当程序运行时 NullPointerException 异常发生。

为了避免上述问题,null 检查需要每个这样存在问题地方。让我们来看看使用 Optional。Guava 提供实用工具类来标准化方式解决上述问题。引入 com.google.common.base.Optional 包。

import com.google.common.base.Optional;

public class GuavaTester {
   public static void main(String args[]){
      GuavaTester guavaTester = new GuavaTester();
      
      Integer invalidInput = null;
      Optional<Integer> a =  Optional.of(invalidInput);
      Optional<Integer> b =  Optional.of(new Integer(10));
      System.out.println(guavaTester.sum(a,b));
   }
   
   public Integer sum(Optional<Integer> a, Optional<Integer> b){
      return a.get() + b.get();
   }
}

运行程序,看到结果如下。

Exception in thread "main" java.lang.NullPointerException
    at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:877)
    at com.google.common.base.Optional.of(Optional.java:103)
    at com.example.test.GuavaTester.main(GuavaTester.java:9)

Java让我们来了解上述程序的一些重要概念。

  • Optional:实用类,使代码使用 null 能够正常。

  • Optional.of:返回要用作参数 Optional 类的实例。检查传递的值是否为 null

  • Optional.get:获取输入存储在 Optional 类的值。

使用 Optional 类,可以方便地查看调用者方法来传递参数正确与否。

Java 8 方式

目前 Guava 中的部分功能,在 Java8 中也有体现,比如,使用引用 java.util.Optional 包。

Exception in thread "main" java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:203)
    at java.util.Optional.<init>(Optional.java:96)
    at java.util.Optional.of(Optional.java:108)
    at com.example.test.GuavaTester.main(GuavaTester.java:11)

五、Guava 快速示例

package com.example.guava;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.*;
import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.*;

public class GuavaTest {

    /**
     * 1、ImmutableList 只读集合
     */
    @Test
    public void testGuava1() {
        // 1、使用 Arrays.asList 创建只读集合
//        List<String> list = Arrays.asList("jack", "tom", "lily");
//        list.add("vince");

//        // 2、使用 Collections.unmodifiableList 创建只读集合
//        List<String> list = new ArrayList<>();
//        list.add("jack");
//        list.add("tom");
//        list.add("lily");
//        List<String> readList = Collections.unmodifiableList(list);
//        readList.add("vince");

        // 3、使用 ImmutableList.of 创建只读集合
        ImmutableList<String> list = ImmutableList.of("jack", "tom", "lily");
        list.add("vince");
    }

    /**
     * 2、函数式编程:过滤器
     */
    @Test
    public void testGuava2() {
        // 使用 Lists.newArrayList 创建的集合非只读
        ArrayList<String> list = Lists.newArrayList("java", "php", "javaScript", "h5", "jackson");

        // 过滤输出以 j 开头的元素
        Collection<String> result = Collections2.filter(list, (e) -> e.startsWith("j"));
        result.forEach(System.out::println);
    }

    /**
     * 3、函数式编程:转换
     */
    @Test
    public void testGuava3() {
        Set<Long> timeSet = Sets.newHashSet(1520446283952L, 1580446283952L, 1542446287952L);
        Collection<String> timeCollect = Collections2.transform(timeSet, (e) -> new SimpleDateFormat("yyyy-MM-dd").format(e));
        timeCollect.forEach(System.out::println);   // 2018-11-17、2018-03-08、2020-01-31
    }

    /**
     * 4、组合式函数编程
     *
     *      1、如果元素长度大于4,截取
     *      2、转换大写
     *      3、转换集合
     */
    @Test
    public void testGuava4() {
        ArrayList<String> list = Lists.newArrayList("java", "php", "javaScript", "h5", "jackson");

        Function<String, String> f1 = (e) -> e.length() > 4 ? e.substring(0, 4) : e;
        Function<String, String> f2 = (e) -> e.toUpperCase();

        // 组合函数
        Function<String, String> f = Functions.compose(f1, f2);

        // 转换
        Collection<String> strCollect = Collections2.transform(list, f);
        strCollect.forEach(System.out::println);
    }

    /**
     * 5、集合操作:交集、差集、并集
     */
    @Test
    public void testGuava5() {
        Set<Integer> set1 = Sets.newHashSet(1, 2, 3);
        Set<Integer> set2 = Sets.newHashSet(3, 4, 5);

        System.out.println("-------- 交集 ------");
        // 交集
        Sets.SetView<Integer> v1 = Sets.intersection(set1, set2);
        v1.forEach(System.out::println);

        System.out.println("\n-------- 差集 ------");
        // 差集
        Sets.SetView<Integer> v2 = Sets.difference(set1, set2);
        v2.forEach(System.out::println);

        System.out.println("\n-------- 并集 ------");
        // 并集
        Sets.SetView<Integer> v3 = Sets.union(set1, set2);
        v3.forEach(System.out::println);
    }

    /**
     * 6、Multiset:无序可重复
     */
    @Test
    public void testGuava6() {
        String str = "good good study day day up";
        String[] ss = str.split(" ");

        HashMultiset<String> multiset = HashMultiset.create();
        for (String s : ss) {
            multiset.add(s);
        }

        Set<String> set = multiset.elementSet();

        // 查看相同元素的个数
        set.forEach(s -> System.out.println(s + " : " + multiset.count(s)));
    }

    /**
     * 7、Multimap key 可以重复
     *
     * 将相同的key合并,value值为list
     */
    @Test
    public void testGuava7() {
        Map<String, String> map = new HashMap<>();
        map.put("Java 从入门到精通", "bin");
        map.put("Android 从入门到精通", "bin");
        map.put("PHP 从入门到精通", "jack");
        map.put("笑看人生", "vince");

        // 创建 ArrayListMultimap 将 map 的key,value 反向存储
        ArrayListMultimap<String, String> listMultimap = ArrayListMultimap.create();
        map.forEach((k, v) -> listMultimap.put(v, k));

        System.out.println(listMultimap);

        System.out.println("\n------ 遍历 ArrayListMultimap -----");

        // 遍历,能看出来有两个 key 为 bin
        listMultimap.forEach((k, v) -> System.out.println(k + " : " + v));

        System.out.println("\n------ 遍历 keySet -----");

        listMultimap.keySet().forEach(k -> {
            List<String> values = listMultimap.get(k);
            System.out.println(k + " : " + values);
        });
    }

    /**
     * 8、BiMap:双向 Map (bidirectional Map)键与值不能重复
     */
    @Test
    public void testGuava8() {
        // 使用场景,比如微信号和手机号绑定
        BiMap<String, String> biMap = HashBiMap.create();
        biMap.put("tingfeng", "13000000000");
        biMap.put("renkui", "18000000000");
        biMap.put("xiaomiao", "15000000000");

        // 使用 inverse 将 key,value 反转
        String username = biMap.inverse().get("13000000000");
        System.out.println("账号:" + username);
    }

    /**
     * 9、双键的 Map --> Table --> rowKey+columnKye+value
     */
    @Test
    public void test1() {
        Table<Object, Object, Object> table = HashBasedTable.create();
        table.put("jack", "java", 98);
        table.put("jack", "php", 65);
        table.put("jack", "ui", 80);
        table.put("jack", "mysql", 86);

        // 遍历
        Set<Table.Cell<Object, Object, Object>> cells = table.cellSet();
        cells.forEach(c -> System.out.println(c.getRowKey() + "-" + c.getColumnKey() + " : " + c.getValue()));
    }

}

六、相关文章



未经允许请勿转载:程序喵 » Google Guava 快速入门 —— Guava介绍

点  赞 (1) 打  赏
分享到: