Google guava学习

文章目录

  • Google guava学习
      • 一、摘要
      • 二、优点
      • 三、maven依赖
      • 四、Guava API使用教程
      • 五、GuavaCache本地内存缓存
      • 六、布隆过滤器

Google guava学习

一、摘要

  • Guava是对JavaAPI的补充,对Java开发中常用功能进行更优雅的实现,使得编码更加轻松,代码容易理解。Guava使用了多种设计模式,同时经过了很多测试,得到了越来越多开发团队的青睐。Java最新版本的API采纳了Guava的部分功能,但依旧无法替代。
  • 中文文档

二、优点

  1. 集合[collections]
  2. 缓存[caching]
  3. 原生类型支持[primitivessupport]
  4. 并发库[concurrencylibraries]
  5. 通用注解[commonannotations]
  6. 字符串处理[stringprocessing]
  7. I/O等等。

三、maven依赖


			com.google.guava
			guava
			19.0
		

四、Guava API使用教程

package com.mtons.mblog.modules.guava;

import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.*;
import com.mtons.mblog.BootApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Map;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = BootApplication.class)
/**
 * Guava API使用教程
 */
public class GuavaTest {

    /**
     * Immutable特点
     * 1.在多线程操作下,是线程安全的。
     *
     * 2.所有不可变集合会比可变集合更有效的利用资源。
     *
     * 3.中途不可改变
     * 输出:
     * iList: [a, b, c]
     * iSet: [e1, e2]
     * iMap: {k1=v1, k2=v2}
     */
    @Test
    public void testGuavaCollection() {
        ImmutableList<String> iList = ImmutableList.of("a", "b", "c");
        ImmutableSet<String> iSet = ImmutableSet.of("e1", "e2");
        ImmutableMap<String, String> iMap = ImmutableMap.of("k1", "v1", "k2", "v2");
        System.out.println("iList: " + iList.toString());
        System.out.println("iSet: " + iSet.toString());
        System.out.println("iMap: " + iMap.toString());
    }
    /**
     *输出:[1, 2]
     */
    @Test
    public void testGuavaMap() {
        Multimap<String,Integer> mapM = ArrayListMultimap.create();
        mapM.put("test",1);
        mapM.put("test",2);
        System.out.println(mapM.get("test"));

    }

    /**
     * Guava 字符串连接器Joiner
     * 输出:嗨,jim|jack|kevin
     */
    @Test
    public void testGuavaJoiner() {
        StringBuilder stringBuilder = new StringBuilder("嗨,");
        // 字符串连接器,以|为分隔符,同时去掉null元素
        Joiner joiner1 = Joiner.on("|").skipNulls();
        // 构成一个字符串jim|jack|kevin并添加到stringBuilder
        stringBuilder = joiner1.appendTo(stringBuilder, "jim", "jack", null, "kevin");
        System.out.println(stringBuilder);
    }

    /**
     * Guava MapToString
     * 输出:Cookies:12332#Content-Length:30000#Date:2018.07.04#Mime:text/html
     */
    @Test
    public void testMapToString() {
        Map<String, String> testMap = Maps.newLinkedHashMap();
        testMap.put("Cookies", "12332");
        testMap.put("Content-Length", "30000");
        testMap.put("Date", "2018.07.04");
        testMap.put("Mime", "text/html");
        // 用:分割键值对,并用#分割每个元素,返回字符串
        String returnedString = Joiner.on("#").withKeyValueSeparator(":").join(testMap);
        System.out.println(returnedString);

    }

    /**
     * Guava MapToString
     * 输出:
     * Cookies -> 12332
     * Content-Length -> 30000
     * Date -> 2018.07.04
     * Mime -> text/html
     */
    @Test
    public void testStringToMap() {
        // 接上一个,内部类的引用,得到分割器,将字符串解析为map
        Splitter.MapSplitter ms = Splitter.on("#").withKeyValueSeparator(':');
        Map<String, String> ret = ms.split("Cookies:12332#Content-Length:30000#Date:2018.07.04#Mime:text/html");
        for (String it2 : ret.keySet()) {
            System.out.println(it2 + " -> " + ret.get(it2));
        }

    }

    /**
     * Guava 字符串工具类Strings
     * 输出:
     * true
     * true
     * false
     * helloTTT
     */
    @Test
    public void testStrings() {
        System.out.println(Strings.isNullOrEmpty("")); // true
        System.out.println(Strings.isNullOrEmpty(null)); // true
        System.out.println(Strings.isNullOrEmpty("hello")); // false
        // 将null转化为""
        System.out.println(Strings.nullToEmpty(null)); // ""

        // 从尾部不断补充T只到总共8个字符,如果源字符串已经达到或操作,则原样返回。类似的有padStart
        System.out.println(Strings.padEnd("hello", 8, 'T')); // helloTTT

    }

    /**
     * Guava 字符匹配器CharMatcher
     */
    @Test
    public void testCharMatcher() {
        // 空白回车换行对应换成一个#,一对一换
        String stringWithLinebreaks = "hello world\r\r\ryou are here\n\ntake it\t\t\teasy";
        String s6 = CharMatcher.BREAKING_WHITESPACE.replaceFrom(stringWithLinebreaks,'#');
        //hello#world###you#are#here##take#it###easy
        System.out.println(s6);

        // 将所有连在一起的空白回车换行字符换成一个#,倒塌
        String tabString = "  hello   \n\t\tworld   you\r\nare             here  ";
        String tabRet = CharMatcher.WHITESPACE.collapseFrom(tabString, '#');
        //#hello#world#you#are#here#
        System.out.println(tabRet);

        // 在前面的基础上去掉字符串的前后空白,并将空白换成一个#
        String trimRet = CharMatcher.WHITESPACE.trimAndCollapseFrom(tabString, '#');
        //hello#world#you#are#here
        System.out.println(trimRet);

        String letterAndNumber = "1234abcdABCD56789";
        // 保留数字
        String number = CharMatcher.JAVA_DIGIT.retainFrom(letterAndNumber);
        //123456789
        System.out.println(number);

    }
}

五、GuavaCache本地内存缓存

package com.mtons.mblog.modules.guava;

import com.google.common.cache.*;
import com.mtons.mblog.BootApplication;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = BootApplication.class)
/**
 * ImmutableMap getAllPresent(Iterable keys) 一次获得多个键的缓存值
 * putAll方法向缓存中添加一个或者多个缓存项
 * invalidateAll方法从缓存中移除缓存项
 * ConcurrentMap快照
 * refresh(Key) 刷新缓存,即重新取缓存数据,更新缓存
 */
public class GuavaCacheTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException{
        //缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
        LoadingCache<Integer,Student> studentCache
                //CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                //设置并发级别为8,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒钟过期
                .expireAfterWrite(8, TimeUnit.SECONDS)
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                .maximumSize(100)
                //设置要统计缓存的命中率
                .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方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
                .build(
                        new CacheLoader<Integer, Student>() {
                            @Override
                            public Student load(Integer key) throws Exception {
                                //这里可以设置数据库查询,放入缓存中
                                System.out.println("load student " + key);
                                Student student = new Student();
                                student.setId(key);
                                student.setName("name " + key);
                                return student;
                            }
                        }
                );

        for (int i=0;i<20;i++) {
            //从缓存中得到数据,由于我们没有设置过缓存,所以需要通过CacheLoader加载缓存数据
            //缓存没有数据会调用load(Integer key),并把查询到的数据放入缓存中
            Student student = studentCache.get(1);
            System.out.println(student);
            //java.util.concurrent.TimeUnit 休眠1秒
            TimeUnit.SECONDS.sleep(1);
        }

        System.out.println("cache stats:");
        //最后打印缓存的命中率等 情况
        System.out.println(studentCache.stats().toString());
    }
}

输出:

load student 1
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
1 was removed, cause is EXPIRED
load student 1
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
1 was removed, cause is EXPIRED
load student 1
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
Student{id=1, name='name 1'}
cache stats:
CacheStats{hitCount=17, missCount=3, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=3308375, evictionCount=2}

六、布隆过滤器

package com.mtons.mblog.modules.guava;

import java.nio.charset.Charset;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink;

/**
 * 布隆过滤器
 *
 * 布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,
 * false positive rate(误报率)越大,但是false negative (漏报)是不可能的。
 * 为了add一个元素,用k个hash function将它hash得到bloom filter中k个bit位,将这k个bit位置1。
 *
 * 为了query一个元素,即判断它是否在集合中,用k个hash function将它hash得到k个bit位。若这k bits全为1,
 * 则此元素在集合中;若其中任一位不为1,则此元素比不在集合中(因为如果在,则在add时已经把对应的k个bits位置为1)。
 *
 * 不允许remove元素,因为那样的话会把相应的k个bits位置为0,而其中很有可能有其他元素对应的位。因此
 * remove会引入false negative,这是绝对不被允许的。
 */
public class BloomTest {
    // 预计元素个数
    private long size = 1024 * 1024;

    private BloomFilter<String> bloom = BloomFilter.create(new Funnel<String>() {
        @Override
        public void funnel(String from, PrimitiveSink into) {
            // 自定义过滤条件 此处不做任何过滤
            into.putString((CharSequence) from, Charset.forName("UTF-8"));
        }
    }, size);

    public void fun() {
        // 往过滤器中添加元素
        bloom.put("布隆过滤器");
        // 查询
        boolean mightContain = bloom.mightContain("布隆过滤器");
        System.out.println(mightContain);
    }

    public static void main(String[] args) {
        BloomTest blBoolmTest = new BloomTest();
        blBoolmTest.fun();
    }
}


package com.mtons.mblog.modules.guava;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class BloomFilterTest {
    private static final int insertions = 1000000;// 100万

    public static void main(String[] args) {
        // 初始化一个存储string数据的布隆过滤器,默认fpp(误差率) 0.03
        BloomFilter<String> bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), insertions);

        Set<String> set = new HashSet<String>(insertions);
        List<String> list = new ArrayList<String>(insertions);

        for (int i = 0; i < insertions; i++) {
            String uuid = UUID.randomUUID().toString();
            bf.put(uuid);
            set.add(uuid);
            list.add(uuid);
        }

        int wrong = 0; // 布隆过滤器误判的次数
        int right = 0;// 布隆过滤器正确次数

        for (int i = 0; i < 10000; i++) {
            String str = i % 100 == 0 ? list.get(i / 100) : UUID.randomUUID().toString();
            if (bf.mightContain(str)) {
                if (set.contains(str)) {
                    right++;
                } else {
                    wrong++;
                }
            }
        }

        //right 为100
        System.out.println("right:" + right);
        //因为误差率为3%,所以一万条数据wrong的值在300左右
        System.out.println("wrong:" + wrong);
    }

}

package com.mtons.mblog.modules.guava;

/**
 * @author Administrator
 */
public class Student {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

你可能感兴趣的:(Google guava学习)