Guava是Google出品的一套Java核心库。相较于Java中自带的一些库来说,使用很方便。推荐使用。
以下示例引用的是guava-18.0.jar
key可以重复的map,子类有ListMultimap和SetMultimap,对应的通过key分别得到list和set
不是集合,可以增加重复的元素,并且可以统计出重复元素的个数
相当于有两个key的map
是一个一一映射,可以通过key得到value,也可以通过value得到key;
大多数Futures 方法中需要它。转到ListenableFuture 编程比较容易。
Guava提供的通用公共类封装了公共的操作方方法,不需要提供Future和ListenableFuture的扩展方法。
1.愿意消耗一些内存空间来提升速度。
2.预料到某些键会被查询一次以上。
3.缓存中存放的数据总量不会超出内存容量。
(GuavaCache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合需求,请尝试Memcached这类工具)
不同的缓存项有不同的“权重”(weights)
可以使用CacheBuilder.weigher(Weigher)指定一个权重函数,
并且用CacheBuilder.maximumWeight(long)指定最大总重
定时回收(Timed Eviction)
expireAfterAccess(long, TimeUnit):
-----缓存项在给定时间内没有被读/写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。
expireAfterWrite(long, TimeUnit):
-----缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变得陈旧不可用,这种回收方式是可取的。
移除监听器
通过CacheBuilder.removalListener(RemovalListener),
可以声明一个监听器,以便缓存项被移除时做一些额外操作。
缓存项被移除时,RemovalListener会获取移除通知[RemovalNotification],其中包含移除原因[RemovalCause]、键和值。
以下示例引用的是guava-18.0.jar
1.Guava对JDK集合的扩展
1.简化集合的创建
Map<String, Map<String, String>> map1 = Maps.newHashMap();
List<List<Map<String, String>>> arrayList = Lists.newArrayList();
List<String> exactly100 = Lists.newArrayListWithCapacity(100);
List<String> linkedList = Lists.newLinkedList();
Set<String> Set = Sets.newHashSet();
Map<String, String> map2 = Maps.newHashMap();
Integer[] intArrays = ObjectArrays.newArray(Integer.class, 10);
2.简化集合的初始化
Set<String> set = Sets.newHashSet("one", "two", "three");
List<String> list1 = Lists.newArrayList("one", "two", "three");
Set<String> set2 = Sets.newHashSet(new String("a"), new String("b"));
Set<String> set1 = ImmutableSet.of("one", "two", "three");// 不可变集合
// 或则调用ImmutableSet.copyOf(set)来创建 不可变集合
Map<String, String> map3 = ImmutableMap.of("ON", "TRUE", "OFF", "FALSE");
// map3.put("a", "c")-----抛出java.lang.UnsupportedOperationException
// Builder工具创建 不可变集合
ImmutableSet<String> set4 = ImmutableSet.<String> builder()
.add(new String("a")).add(new String("b")).add(new String("a"))
.build();
System.out.println(set4);// [a, d]
// 对有序不可变集合来说,排序是可以在构造集合的时候完成
Set<String> set5 = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
System.out.println(set5);// [a, b, c, d]
// asList视图,所有不可变集合都有一个asList()方法提供ImmutableList视图
System.out.println(set4.asList().get(1));// b
3.新的集合类型
3.1 MultiMapkey可以重复的map,子类有ListMultimap和SetMultimap,对应的通过key分别得到list和set
customersByType = ArrayListMultimap.create();
customersByType.put("abc", new String("aaa"));
customersByType.put("abc", new String("bbb"));
customersByType.put("abc", new String("ccc"));
customersByType.put("abc", new String("ddd"));
customersByType.put("abcd", new String("eee"));
customersByType.put("abcde", new String("fff"));
// 以集合形式返回键所对应的值视图,即使没有任何对应的值,也会返回空集合
System.out.println(customersByType.get("abc"));// aaa bbb ccc ddd
// ListMultimap.get(key)返回List,SetMultimap.get(key)返回Set。
3.2 MultiSet(场景:统计一个词在文档中出现了多少次)不是集合,可以增加重复的元素,并且可以统计出重复元素的个数
// Multiset元素的顺序是无关紧要的:Multiset {a, a, b}和{a, b, a}是相等的
Multiset<Integer> multiSet = HashMultiset.create();
multiSet.add(10);
multiSet.add(30);
multiSet.add(30);
multiSet.add(40);
System.out.println(multiSet.count(30)); // 2
System.out.println(multiSet.size()); // 4
// add(E, int)------增加给定元素在Multiset中的计数
// remove(E, int)------减少给定元素在Multiset中的计数
// setCount(E, int)-----设置给定元素在Multiset中的计数,不可以为负数
3.3 Table相当于有两个key的map
Table<Integer, Integer, String> personTable = HashBasedTable.create();
personTable.put(1, 20, new String("1--20"));
personTable.put(0, 30, new String("0--30"));
personTable.put(0, 25, new String("0--25"));
personTable.put(1, 50, new String("1--50"));
personTable.put(0, 27, new String("0--27"));
personTable.put(1, 29, new String("1--29"));
personTable.put(0, 33, new String("0--33"));
personTable.put(1, 66, new String("1--66"));
// 得到行集合
Map<Integer, String> rowMap = personTable.row(0);
System.out.println(rowMap);// {25=0--25, 33=0--33, 27=0--27,
// 30=0--30}
int maxAge = Collections.max(rowMap.keySet());
// System.out.println(maxAge);// 33
3.4 BiMap是一个一一映射,可以通过key得到value,也可以通过value得到key;
BiMap<Integer, String> biMap = HashBiMap.create();
biMap.put(1, "hello");
biMap.put(2, "helloa");
biMap.put(3, "world");
biMap.put(4, "worldb");
biMap.put(5, "my");
biMap.put(6, "myc");
int value = biMap.inverse().get("my");
System.out.println("my--" + value + ", " + value + "--"
+ biMap.get(value));
2. 处理null或空
Guava用Optional<T>表示可能为null的T类型引用。一个Optional实例可能包含非null的引用(称之为引用存在),也可能什么也不包括(称之为引用缺失)。它从不说包含的是null值,而是用存在或缺失来表示。 但Optional从不会包含null值引用。Optional<Integer> possible = Optional.of(5);
// Optional.of(T)----
// 创建指定引用的Optional实例,若引用为null则快速失败,抛出java.lang.NullPointerException
// Optional.absent()-----创建引用缺失的Optional实例
// Optional.fromNullable(T)-----
// 创建指定引用的Optional实例,若引用为null则表示缺失(即Optional.absent())
// .isPresent()---
// 如果Optional包含非null的引用(引用存在),返回true
possible.isPresent();
System.out.println(possible.isPresent());// returns true
// .get()---
// 返回Optional所包含的引用,若引用缺失,则抛出java.lang.IllegalStateException
possible.get();
System.out.println(possible.get());// returns 5
// .or(T)---
// 返回Optional所包含的引用,若引用缺失,返回指定的值
possible.or(1);
// .orNull()---
// 返回Optional所包含的引用,若引用缺失,返回null
possible.orNull();
// 处理null或空字符
String aString = "";
String bString = null;
String cString = "aaa";
System.out.println(Strings.emptyToNull(aString));//null
System.out.println(Strings.emptyToNull(bString));//null
System.out.println(Strings.emptyToNull(cString));//aaa
System.out.println(Strings.nullToEmpty(aString));//空("")
System.out.println(Strings.nullToEmpty(bString));//空("")
System.out.println(Strings.nullToEmpty(cString));//aaa
System.out.println(Strings.isNullOrEmpty(aString));//true
System.out.println(Strings.isNullOrEmpty(bString));//true
System.out.println(Strings.isNullOrEmpty(cString));//false
3.排序器Ordering
List<String> list = Lists.newArrayList("22", "a", "bb", "11", "ccc");
// Ordering.natural()-------对可排序类型做自然排序,如数字按大小,日期按先后排序
list = Ordering.natural().sortedCopy(list);
System.out.println(list);// [11, 22, a, bb, ccc]
// Ordering.usingToString()------按对象的字符串形式做字典排序
list = Ordering.usingToString().sortedCopy(list);
System.out.println(list);// [11, 22, a, bb, ccc]
// Ordering.from(comparator)-------把给定的Comparator转化为排序器
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
return o1.hashCode() - o2.hashCode();
}
};
list = Ordering.from(comparator).sortedCopy(list);
System.out.println(list);// [a, 11, 22, bb, ccc]
// 实现自定义的排序器时,除了用上面的from方法,也可以跳过实现Comparator,而直接继承Ordering:
Ordering<String> byLenOrdering = new Ordering<String>() {
public int compare(String left, String right) {
return Ints.compare(left.length(), right.length());
}
};
list = byLenOrdering.sortedCopy(list);
System.out.println(list);// [a, 11, 22, bb, ccc]
// 链式调用方法:通过链式调用,可以由给定的排序器衍生出其它排序器
// 1.reverse()-----获取语义相反的排序器
// 2.nullsFirst()-----使用当前排序器,但额外把null值排到最前面
// 3.nullsLast()-----使用当前排序器,但额外把null值排到最后面
// 4.compound(Comparator)-----合成另一个比较器,以处理当前排序器中的相等情况
// -------用compound方法包装排序器时,就不应遵循从后往前读的原则。
// -------为了避免理解上的混乱,请不要把compound写在一长串链式调用的中间,你可以另起一行,在链中最先或最后调用compound。
// 5.lexicographical()-----基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>的排序器
// 6.onResultOf(Function)-----对集合中元素调用Function,再按返回值用当前排序器排序
list = byLenOrdering.reverse().sortedCopy(list);
System.out.println(list);// [ccc, 11, 22, bb, a]
4.String处理工具
1.连接器[Joiner]public static void testJoiner() {
// .on("; ")以,分隔 ;.skipNulls()忽略null
Joiner joiner = Joiner.on("; ").skipNulls();
String aString = joiner.join("aaa", null, "bbb", "ccc");
System.out.println(aString);// aaa; bbb; ccc
// useForNull(String)方法可以给定某个字符串来替换null
joiner = Joiner.on("; ").useForNull("ccc");
aString = joiner.join("aaa", null, "bbb", "ccc");
System.out.println(aString);// aaa; ccc; bbb; ccc
Joiner.on(";").join(Arrays.asList(1, 5, 7)); // returns "1;5;7"
// joiner实例总是不可变的。用来定义joiner目标语义的配置方法总会返回一个新的joiner实例。
// 这使得joiner实例都是线程安全的,你可以将其定义为static final常量。
}
2.拆分器[Splitter]public static void testSplitter() {
// String.split悄悄丢弃了尾部的分隔符
String[] strs = ",a,,b,".split(",");
System.out.println(Arrays.toString(strs));// [, a, , b]
//omitEmptyStrings()-----从结果中自动忽略空字符串
//trimResults()-----移除结果字符串的前导空白和尾部空白
//trimResults(CharMatcher)-----给定匹配器,移除结果字符串的前导匹配字符和尾部匹配字符
//limit(int)-----限制拆分出的字符串数量
Iterable<String> strsIt = Splitter.on(',').trimResults()
.omitEmptyStrings().split(",a,,b,");//[a, b]
Iterator<String> it = strsIt.iterator();
while(it.hasNext())
System.out.println(it.next());
}
5.并发[Concurrency]
Guava 定义了 ListenableFuture接口并继承了JDK concurrent包下的Future 接口。大多数Futures 方法中需要它。转到ListenableFuture 编程比较容易。
Guava提供的通用公共类封装了公共的操作方方法,不需要提供Future和ListenableFuture的扩展方法。
public static void testListenableFuture() throws InterruptedException,
ExecutionException {
// ListeningExecutorService 接口, 该接口返回 ListenableFuture
// 而相应的 ExecutorService 返回普通的 Future。
// 将 ExecutorService 转为
// ListeningExecutorService,可以使用MoreExecutors.listeningDecorator(ExecutorService)进行装饰。
ListeningExecutorService service = MoreExecutors
.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture future = service.submit(new Callable() {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "aaaa";
}
});
service.shutdown();
System.out.println(future.get());// aaaa
// ListenableFuture可以注册回调方法(callbacks),在运算(多线程执行)完成的时候进行调用,
// 或者在运算(多线程执行)完成后立即执行。这样简单的改进,使得可以明显的支持更多的操作,
// 在JDKconcurrent中的Future是不支持的。
// *********************************************************
// Callback采用轻量级的设计. FutureCallback<V> 中实现了两个方法:
// onSuccess(V),在Future成功的时候执行,根据Future结果来判断。
// onFailure(Throwable), 在Future失败的时候执行,根据Future结果来判断。
Futures.addCallback(future, new FutureCallback() {
@Override
// future执行任务成功后,执行onSuccess,result值为future.get()
public void onSuccess(Object result) {
System.out.println("onSuccess---" + result);// onSuccess---aaaa
}
@Override
public void onFailure(Throwable t) {
System.out.println("onFailure---" + t.toString());
}
});
// ListenableFuture 中addListener(Runnable, Executor),
// 该方法会在多线程运算完的时候,指定的Runnable参数传入的对象会被指定的Executor执行。
}
public static void testService() throws Exception {
MyService myService = new MyService();
// myService.startUp();
// myService.shutDown();
}
class MyService extends AbstractIdleService {
@Override
protected void startUp() throws Exception {
System.out.println("startUp()");
}
@Override
protected void shutDown() throws Exception {
// TODO Auto-generated method stub
System.out.println("shutDown()");
}
}
6.缓存
通常来说,Guava Cache适用于:1.愿意消耗一些内存空间来提升速度。
2.预料到某些键会被查询一次以上。
3.缓存中存放的数据总量不会超出内存容量。
(GuavaCache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合需求,请尝试Memcached这类工具)
// LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
// .maximumSize(1000)
// .expireAfterWrite(10, TimeUnit.MINUTES)
// .removalListener(MY_LISTENER)
// .build(
// new CacheLoader<Key, Graph>() {
// public Graph load(Key key) throws AnyException {
// return createExpensiveGraph(key);
//
//
// }
// }});
// CacheLoader
// LoadingCache是附带CacheLoader构建而成的缓存实现。
// 创建自己的CacheLoader通常只需要简单地实现V load(K key) throws Exception方法。
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS).maximumSize(1000)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
// 实现了模式"如果有缓存则返回;否则运算、缓存、然后返回"。
return "null";
}
});
cache.put("a", "aaaaaa");
try {
System.out.println(cache.get("a"));// aaaaaa
System.out.println(cache.get("bb"));// null----key不存在,使用CacheLoader向缓存原子地加载新值
} catch (ExecutionException e) {
e.printStackTrace();
}
// 也可以在调用get时,指定Callable
Cache<String, String> cache1 = CacheBuilder.newBuilder()
.maximumSize(1000)// 规定缓存项的数目不超过固定值,逼近限定值时将尝试回收最近没有使用或总体上很少使用的缓存项。
.build(); // no CacheLoader
try {
// If the key wasn't in the "easy to compute" group,
// we need to do things the hard way.
String aString = cache1.get("a", new Callable<String>() {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "nullnullnull";
}
});
System.out.println(aString);
} catch (ExecutionException e) {
e.printStackTrace();
}
不同的缓存项有不同的“权重”(weights)
可以使用CacheBuilder.weigher(Weigher)指定一个权重函数,
并且用CacheBuilder.maximumWeight(long)指定最大总重
定时回收(Timed Eviction)
expireAfterAccess(long, TimeUnit):
-----缓存项在给定时间内没有被读/写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。
expireAfterWrite(long, TimeUnit):
-----缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变得陈旧不可用,这种回收方式是可取的。
移除监听器
通过CacheBuilder.removalListener(RemovalListener),
可以声明一个监听器,以便缓存项被移除时做一些额外操作。
缓存项被移除时,RemovalListener会获取移除通知[RemovalNotification],其中包含移除原因[RemovalCause]、键和值。