寒玉 Blog
  • Home
  • Books
  • About Me
  • Categories
  • Tags
  • Archives

JAVA8 Guava


Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, 等等. 这些高质量的 API 可以使你的JAVa代码更加优雅,更加简洁,让你工作更加轻松愉悦。

项目相关信息:

  • 官方首页:http://code.google.com/p/guava-libraries
  • 官方下载:http://code.google.com/p/guava-libraries/downloads/list
  • 官方文档:http://docs.guava-libraries.googlecode.com/git/javadoc
  • http://www.ostools.net/apidocs/apidoc?api=guava

源码包的简单说明:

  • 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:多线程工具包。

类库使用手册

一. 基本工具类:

  1. 使用和避免 null:null 有语言歧义, 会产生令人费解的错误, 反正他总是让人不爽。很多 Guava 的工具类在遇到 null 时会直接拒绝或出错,而不是默默地接受他们。
  2. 前提条件:更容易的对你的方法进行前提条件的测试。
  3. 常见的对象方法: 简化了Object常用方法的实现, 如 hashCode() 和 toString()。
  4. 排序: Guava 强大的 "fluent Comparator"比较器, 提供多关键字排序。
  5. Throwable类: 简化了异常检查和错误传播。

二. 集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。

  1. Immutable collections(不变的集合): 防御性编程, 不可修改的集合,并且提高了效率。
  2. New collection types(新集合类型):JDK collections 没有的一些集合类型,主要有:multisets,multimaps,tables, bidirectional maps等等
  3. Powerful collection utilities(强大的集合工具类): java.util.Collections 中未包含的常用操作工具类
  4. Extension utilities(扩展工具类): 给 Collection 对象添加一个装饰器? 实现迭代器? 我们可以更容易使用这些方法。

三. 缓存: 本地缓存,可以很方便的操作缓存对象,并且支持各种缓存失效行为模式。

四. Functional idioms(函数式): 简洁, Guava实现了Java的函数式编程,可以显著简化代码。

五. Concurrency(并发):强大,简单的抽象,让我们更容易实现简单正确的并发性代码。

  1. ListenableFuture(可监听的Future): Futures,用于异步完成的回调。   
  2. Service: 控制事件的启动和关闭,为你管理复杂的状态逻辑。

六. Strings: 一个非常非常有用的字符串工具类: 提供 splitting,joining, padding 等操作。

七. Primitives: 扩展 JDK 中未提供的对原生类型(如int、char等)的操作, 包括某些类型的无符号的变量。

八. Ranges: Guava 一个强大的 API,提供 Comparable 类型的范围处理, 包括连续和离散的情况。

九. I/O: 简化 I/O 操作, 特别是对 I/O 流和文件的操作, for Java 5 and 6.

十. Hashing: 提供比 Object.hashCode() 更复杂的 hash 方法, 提供 Bloom filters.

十一. EventBus: 基于发布-订阅模式的组件通信,但是不需要明确地注册在委托对象中。

十二. Math: 优化的 math 工具类,经过完整测试。

十三. Reflection: Guava 的 Java 反射机制工具类。

Optional

大多数情况下开发人员使用null表示是目中缺失情况,可能是已经有一个默认值,或者没有值,或者找不到值.例如,Map.get返回null就表示找不到给定键对应的值

Guava用Optional表示可能为null的T类型引用。一个Optional实例可能包含非null的引用(我们称之为引用存在),也可能什么也不包括(称之为引用缺失)。它从不说包含的是null值,而是用存在或缺失来表示。但Optional从不会包含null值引用。

Optional<Integer> possible = Optional.of(5);
possible.isPresent();
possible.get();

创建Optional实例

method note
Optional.of(T) 创建指定引用的Optional实例,如果引用为null,则迅速失败
Optional.absent() 创建引用缺失的Optional实例
Optional.fromNullable(T) 创建指定引用的Optional实例,若引用为null则表示缺失

用Optional实例查询引用

method note
boolean isPresent() 如果Optional包含非null的引用,返回true
T get() 返回Optional所包含的引用,若引用缺失则抛出java.lang.IllegalStateException
T or(T) 返回Optional所包含的引用,若引用缺失则返回指定的值
T orNull() 返回Optional所包含的引用,若引用缺失则返回null
Set asSet() 返回Optional所包含的引用的单例不可变集,如果引用存在只有单一元素的集合,如果引用缺失,返回一个空集合

好的做法是积极地把null和空区分开,以表示不同的含义,在代码中把null和空同等对待是一种令人不安的坏味道

Guava – Preconditions

Guava Preconditions类中提供了若干前置条件判断的实用方法,建议使用

方法声明(不包括额外参数) 描述 检查失败时抛出的异常
checkArgument(boolean) 检查boolean是否为true,用来检查传递给方法的参数。 IllegalArgumentException
checkNotNull(T) 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull。 NullPointerException
checkState(boolean) 用来检查对象的某些状态。 IllegalStateException
checkElementIndex(int index, int size) 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size * IndexOutOfBoundsException
checkPositionIndex(int index, int size) 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size * IndexOutOfBoundsException
checkPositionIndexes(int start, int end, int size) 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效* IndexOutOfBoundsException

Guava – Maps

Create Map

Map<String, String> aNewMap = Maps.newHashMap();

ImmutableMap

@Test
public void whenCreatingImmutableMap_thenCorrect() {
    Map<String, Integer> salary = ImmutableMap.<String, Integer> builder()
      .put("John", 1000)
      .put("Jane", 1500)
      .put("Adam", 2000)
      .put("Tom", 2000)
      .build();
    assertEquals(1000, salary.get("John").intValue());
    assertEquals(2000, salary.get("Tom").intValue());
}

SortedMap

@Test
public void whenUsingSortedMap_thenKeysAreSorted() {
    ImmutableSortedMap<String, Integer> salary = new ImmutableSortedMap
      .Builder<String, Integer>(Ordering.natural())
      .put("John", 1000)
      .put("Jane", 1500)
      .put("Adam", 2000)
      .put("Tom", 2000)
      .build();

    assertEquals("Adam", salary.firstKey());
    assertEquals(2000, salary.lastEntry().getValue().intValue());
}

BiMap

@Test
public void whenCreateBiMap_thenCreated() {
    BiMap<String, Integer> words = HashBiMap.create();
    words.put("First", 1);
    words.put("Second", 2);
    words.put("Third", 3);
    assertEquals(2, words.get("Second").intValue());
    assertEquals("Third", words.inverse().get(3));
}

Multimap

@Test
public void whenCreateMultimap_thenCreated() {
    Multimap<String, String> multimap = ArrayListMultimap.create();
    multimap.put("fruit", "apple");
    multimap.put("fruit", "banana");
    multimap.put("pet", "cat");
    multimap.put("pet", "dog");
    assertThat(multimap.get("fruit"), containsInAnyOrder("apple", "banana"));
    assertThat(multimap.get("pet"), containsInAnyOrder("cat", "dog"));
}

Table

@Test
public void whenCreatingTable_thenCorrect() {
    Table<String,String,Integer> distance = HashBasedTable.create();
    distance.put("London", "Paris", 340);
    distance.put("New York", "Los Angeles", 3940);
    distance.put("London", "New York", 5576);

    assertEquals(3940, distance.get("New York", "Los Angeles").intValue());
    assertThat(distance.columnKeySet(), 
      containsInAnyOrder("Paris", "New York", "Los Angeles"));
    assertThat(distance.rowKeySet(), containsInAnyOrder("London", "New York"));
}

@Test
public void whenTransposingTable_thenCorrect() {
    Table<String,String,Integer> distance = HashBasedTable.create();
    distance.put("London", "Paris", 340);
    distance.put("New York", "Los Angeles", 3940);
    distance.put("London", "New York", 5576);

    Table<String, String, Integer> transposed = Tables.transpose(distance);

    assertThat(transposed.rowKeySet(), 
      containsInAnyOrder("Paris", "New York", "Los Angeles"));
    assertThat(transposed.columnKeySet(), containsInAnyOrder("London", "New York"));
}

ClassToInstanceMap

@Test
public void whenCreatingClassToInstanceMap_thenCorrect() {
    ClassToInstanceMap<Number> numbers = MutableClassToInstanceMap.create();
    numbers.putInstance(Integer.class, 1);
    numbers.putInstance(Double.class, 1.5);

    assertEquals(1, numbers.get(Integer.class));
    assertEquals(1.5, numbers.get(Double.class));
}

Group List using Multimap

@Test
public void whenGroupingListsUsingMultimap_thenGrouped() {
    List<String> names = Lists.newArrayList("John", "Adam", "Tom");
    Function<String,Integer> func = new Function<String,Integer>(){
        public Integer apply(String input) {
            return input.length();
        }
    };
    Multimap<Integer, String> groups = Multimaps.index(names, func);

    assertThat(groups.get(3), containsInAnyOrder("Tom"));
    assertThat(groups.get(4), containsInAnyOrder("John", "Adam"));
}

Guava StopWatch

import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;

public class GuavaStopWatch {
    public static void main(String[] args) {
        printTitle("StopWatch Start ");
        int countingDown=10;
        Stopwatch stopwatch=Stopwatch.createUnstarted();
        stopwatch.elapsed(TimeUnit.SECONDS);
        stopwatch.start();
        while(countingDown>0){
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                println(e.getMessage());
            }
            println("StopWatch Is Running ? --> "+stopwatch.isRunning());
            println("StopWatch Time is "+stopwatch);
            countingDown--;
        }
        printTitle("End Of Looping");
        println("Check Total Time is Needed: "+stopwatch);
        stopwatch.stop();

    }
}

GuavaCache

Guava Cache是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效。

Guava官网介绍,下面的这几种情况可以考虑使用Guava Cache:

  • 愿意消耗一些内存空间来提升速度。
  • 预料到某些键会被多次查询。
  • 缓存中存放的数据总量不会超出内存容量。
<dependency>  
    <groupId>com.google.guava</groupId>  
    <artifactId>guava</artifactId>  
    <version>19.0</version>  
</dependency>  

构建缓存对象

接口Cache代表一块缓存,它有如下方法:

public interface Cache<K, V> {
    V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;

    ImmutableMap<K, V> getAllPresent(Iterable<?> keys);

    void put(K key, V value);

    void putAll(Map<? extends K, ? extends V> m);

    void invalidate(Object key);

    void invalidateAll(Iterable<?> keys);

    void invalidateAll();

    long size();

    CacheStats stats();

    ConcurrentMap<K, V> asMap();

    void cleanUp();
}

可以通过CacheBuilder类来构建一个缓存对象,CacheBuilder类采用builder设计模式,它的每个方法都返回CacheBuilder本身,直到builder()方法被调用,构建一个缓存对象的代码如下:

public class StudyGuavaCache {
    public static void main(String[] args) {
        Cache<String,String> cache = CacheBuilder.newBuilder().build();
        cache.put("word","Hello Guava Cache");
        System.out.println(cache.getIfPresent("word"));
    }
}

上面的代码通过CacheBuilder.newBuilder().build()这句代码创建了一个Cache缓存对象,并在缓存对象中存储了key为word,value为Hello Guava Cache的一条记录。可以看到Cache非常类似于JDK中的Map,但是相比于Map,Guava Cache提供了很多更强大的功能。

设置最大存储

Guava Cache可以设置在构建缓存对象的时候指定缓存所存储的最大记录数量.当Cache中的记录数量达到最大值后再调用put方法向其中添加对象Guava会先从当前缓存的对象记录中选择一条删除掉,腾出空间后再将新的对象存储到Cache中。

public class StudyGuavaCache {
    public static void main(String[] args) {
        Cache<String,String> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .build();
        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");
        System.out.println("第一个值:" + cache.getIfPresent("key1"));
        System.out.println("第二个值:" + cache.getIfPresent("key2"));
        System.out.println("第三个值:" + cache.getIfPresent("key3"));
    }
}

上面代码在构造缓存对象时,通过CacheBuilder类的maximumSize方法指定Cache最多可以存储两个对象,然后调用Cache的put方法向其中添加了三个对象。程序执行结果如下图所示,可以看到第三条对象记录的插入,导致了第一条对象记录被删除。

移除监听器

可以为Cache对象添加一个移除监听器,这样当有记录被删除时可以感知到这个事件。

public class StudyGuavaCache {
    public static void main(String[] args) throws InterruptedException {
        RemovalListener<String, String> listener = new RemovalListener<String, String>() {
            public void onRemoval(RemovalNotification<String, String> notification) {
                System.out.println("[" + notification.getKey() + ":" + notification.getValue() + "] is removed!");
            }
        };
        Cache<String,String> cache = CacheBuilder.newBuilder()
                .maximumSize(3)
                .removalListener(listener)
                .build();
        Object value = new Object();
        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");
        cache.put("key4","value3");
        cache.put("key5","value3");
        cache.put("key6","value3");
        cache.put("key7","value3");
        cache.put("key8","value3");
    }
}

removalListener方法为Cache指定了一个移除监听器,这样当有记录从Cache中被删除时,监听器listener就会感知到这个事件。程序运行结果如下图所示

https://s1.ax1x.com/2018/04/14/CZ11q1.jpg

参考

http://ifeve.com/google-guava-collectionutilities/

Guava Cache用法介绍


  • « JAVA8 Lambda
  • Hadoop mapreduce multiple files »

Published

12 28, 2017

Last Updated

2017-12-28 18:46:53+08:00

Category

java

Tags

  • guava 1
  • java 15
  • jvm 9
  • Powered by Pelican. Theme: Elegant by Talha Mansoor