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:多线程工具包。
类库使用手册
一. 基本工具类:
- 使用和避免 null:null 有语言歧义, 会产生令人费解的错误, 反正他总是让人不爽。很多 Guava 的工具类在遇到 null 时会直接拒绝或出错,而不是默默地接受他们。
- 前提条件:更容易的对你的方法进行前提条件的测试。
- 常见的对象方法: 简化了Object常用方法的实现, 如 hashCode() 和 toString()。
- 排序: Guava 强大的 "fluent Comparator"比较器, 提供多关键字排序。
- Throwable类: 简化了异常检查和错误传播。
二. 集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。
- Immutable collections(不变的集合): 防御性编程, 不可修改的集合,并且提高了效率。
- New collection types(新集合类型):JDK collections 没有的一些集合类型,主要有:multisets,multimaps,tables, bidirectional maps等等
- Powerful collection utilities(强大的集合工具类): java.util.Collections 中未包含的常用操作工具类
- Extension utilities(扩展工具类): 给 Collection 对象添加一个装饰器? 实现迭代器? 我们可以更容易使用这些方法。
三. 缓存: 本地缓存,可以很方便的操作缓存对象,并且支持各种缓存失效行为模式。
四. Functional idioms(函数式): 简洁, Guava实现了Java的函数式编程,可以显著简化代码。
五. Concurrency(并发):强大,简单的抽象,让我们更容易实现简单正确的并发性代码。
- ListenableFuture(可监听的Future): Futures,用于异步完成的回调。
- 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
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 |
返回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就会感知到这个事件。程序运行结果如下图所示