1、简介(下载地址)
Guava是Ggoole基于jdk1.6的类库集合的扩展项目,目的是简化代码,使代码更加的优雅。
1.1、基本库介绍
com.google.common.annotations 注解包
com.google.common.reflects 反射工具包
com.google.common.base 基本工具包
com.google.common.collector 带泛型集合工具包
com.google.common.io io工具包
com.google.common.net 网络包
com.google.common.math 计算包
com.google.common.eventbus 事件总线
com.google.common.concurrent 多线程工具包
com.google.common.hash 哈希包
com.google.common.caching 缓存工具包
com.google.common.primitives 八种基本数据类型和无数据类型的静态工具包
1.2、学习路线
基本工具包
使用和避免null
Null是一个关键字,代表不确定的对象,可以赋值给对象Null值,不可对基本数据类型赋Null,也不可对该变量进行操作,Null可能会造成一些不好的结果。
使用场景:
1、避免编译器报错。
2、释放内存,将对象置为空,等待垃圾回收器回收。
引发问题及解决方式
null表示不确定的对象,但使用的时候回造成二义性,例如从Map中取值,返回值为null时,可能是不存在指定的key,也有可能是key对应的value为空,也没有确切的定义,使用其他的值(非null)可以使代码更加的清晰,相反,在某些情况下使用null是正确的选择,因为在内存消耗和效率方面考虑,使用null更加的廉价,所以,问题的关键在于null能不能指明null到底代表了什么含义。
Guava中的Optional
若T类型可以为null,Optional是将以非空值来替代T类型的方法。一个Optional对象可以包含一个非空T的引用,也可以包含一个不包括任何东西的引用,但Optional从来不会包含一个null的引用。
1、常用静态方法
Optional.of(T):返回一个Optional对象,若T为null,则立即报错。
Optional.absent():返回一个Optional对象,内部包含null值。
Optional.fromNumable(T):接受一个T类型转换为Optional对象,T可以为null。
Optional<Integer> op1 = Optional.of(6); // 直接NullPointException
Optional<Integer> op2 = Optional.fromNullable(null);
Optional<Integer> op3 = Optional.absent();
if (op1.isPresent()) {
System.out.println("op1不为空");
}
if (op2.isPresent()) {
System.out.println("op2不为空");
}
if (op3.isPresent()) {
System.out.println("op3不为空");
}
// 输出 op1不为空
2、实例方法
isPresent() //如果Optional包含的T实例为空,返回false,否则返回true
or(default) //
if (op3.isPresent()) {
System.out.println(op3.get());
}else {
System.out.println(op3.or(666));
}
System.out.println(op3.orNull());
op3.asSet();
优点:除了给null值操作代码阅读性提高之外,Optional的操作是傻瓜式的,要想取值必须要经过Optional,所以你必须要思考null值得合法性。
前提条件
常见对象方法
排序:Comparator比较器
Throwable类:简化异常检查和错误传播
数据类型相关
Primitives
Strings
Ranges
math
集合&&函数式编程
Multiset:
list是有序可重复的,set是无序不可重复的,multiset是这两个集合的灰色地带,
有点类似于map,但和map又有些不同,以下几点体现:
1、新增了count相关方法
2、重复次数只能是正整数(int)
3、setCount(ele,0)相当于删除了所有元素
4、setCount(ele,old,new)当old与集合中的个数不一致时,该方法无效。
其他相同。
public class TestCollection {
// Multiset(允许重复值的Set,但不保证顺序)
public static void testMultiSet() {
String word = "q|qwe|qwe|qwer|qwer|qwer|asd|sdfg|sdfsfsdfs";
String[] wordArr = word.split("\|");
List<String> wordList = Arrays.asList(wordArr);
Map<String, Integer> countMap = new HashMap<String, Integer>();
// 记录集合中不同字符出现的次数(HashMap实现)
wordList.stream().forEach((re) -> {
Integer count = countMap.get(re);
if(count == null) {
countMap.put(re, 1);
}else {
countMap.put(re, count+1);
}
});
System.out.println("countMap:");
for(String key:countMap.keySet()) {
System.out.println(key+"->"+countMap.get(key));
}
// 记录集合中不同字符出现的次数(MultiSet实现)
Multiset<String> set = HashMultiset.create();
set.addAll(wordList);
for(String key:set.elementSet()) {
System.out.println(key+"=>"+set.count(key));
}
System.out.println("*********************************************");
set.add("perl", 6);
for(String key:set.elementSet()) {
System.out.println(key+"=>"+set.count(key));
}
System.out.println("*********************************************");
set.setCount("perl", 66);
for(String key:set.elementSet()) {
System.out.println(key+"=>"+set.count(key));
}
set.setCount("perl", 8, 88);
System.out.println("*********************************************");
for(String key:set.elementSet()) {
System.out.println(key+"=>"+set.count(key));
}
}
public static void main(String[] args) {
testMultiSet();
}
}
Multimap:
是一个一个键对应多个值的数据结构,支持一系列强大的视图功能。
1、asMap方法可以将multimap转化为Map<K, collection
2、entries()返回一个展现形式为Collection<Map.entry<K,V>>的视图。
3、keySet() 返回一个不重复键的Set
4、keys() 返回重复键的set
5、values() 返回一个类似迭代器的Collection
尽管与Map相似,但二者是不同的。
1、multimap总是返回一个空的集合,但这并不代表multimap使用内存进行关联,相反,这个集合只是一个只允许添加操作的视图,如果想要键不存在返回null,则需要调用asMamp方法转为Map<K, collection
2、containsKey(key)当key存在时才会返回true
3、entries()返回所有键值对,想要获取 <K, collection
4、size返回集合所有元素个数,想要获取不同的key个数,使用keySet().size()
// Multimap 一个可以将一个键对应到多个值的结构
public static void multimapTest() {
// HashMap实现多层数据嵌套
for(int i=0;i<20;i++) {
Score score = new Score(i,88+i);
addScore("zhangsan",score);
}
System.out.println(scoreMap.size());
System.out.println(scoreMap.containsKey("zhangsan"));
System.out.println(scoreMap.containsKey("perl"));
List<Score> erp = scoreMap.get("zhangsan");
if (erp != null) {
for(Score score :erp) {
//System.out.println(score);
}
}
// Multimap实现
Multimap<String, Score> scoreMultimap = ArrayListMultimap.create();
for(int i=0;i<20;i++) {
Score score = new Score(i,88+i);
scoreMultimap.put("zhangsan",score);
}
// System.out.println(scoreMultimap.size());
// System.out.println(scoreMultimap.keys());
// 清空数据
// scoreMultimap.clear();
// Score newScore = new Score(1, 99);
// scoreMultimap.put("lisi", newScore);
// System.out.println(scoreMultimap.size());
// System.out.println(scoreMultimap.keys());
Collection<Score> collections = scoreMultimap.values();
for(Score score :collections) {
//System.out.println(score);
}
if (scoreMultimap.asMap().get("2") == null) {
System.out.println(1);
}
// 常用方法
for(int r=10;r<20;r++) {
Score msi = new Score(1000+r, 2000-r);
scoreMultimap.put("msi", msi);
}
System.out.println(scoreMultimap.keySet());
System.out.println(scoreMultimap.keys());
System.out.println(scoreMultimap.values());
System.out.println(scoreMultimap.size());
System.out.println(scoreMultimap.keySet().size());
}
public static void addScore(String name, final Score score) {
List<Score> scores = scoreMap.get(name);
if(scores == null) {
scores = new ArrayList<Score>();
scoreMap.put(name, scores);
}
scores.add(score);
}
class Score{
private int custormId;
private int score;
public int getCustormId() {
return custormId;
}
public void setCustormId(int custormId) {
this.custormId = custormId;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public Score(int custormId,int score) {
this.custormId = custormId;
this.score = score;
}
@Override
public String toString() {
return "Score [custormId=" + custormId + ", score=" + score + "]";
}
}
Multimap的实现:
Implemention | keys的行为类似 | values的行为类似 |
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap | LinkedMap | LinkedList |
LinkedHashMultiMap | LinkedHashMap | LinkedSet |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
注意: 除Immutable实现外都支持空键和空值。
1、LinkedListMultimap.entries()可维持遍历的顺序
2、LinkedHashMultimap可维持插入的顺序
并不是所有的MultiMap都实现了Map<K,Collection<K,V>>结构,为了最小化开销,使用了自定义的hash table
总结:该集合类似于Map,并基于Map提供了很多实现,主要区别为asMap方法。
BiMap
键和值双向关联的数据结构
问题:
value重复转换为key会被覆盖问题
数据是否需要关联更新
特点:
使用BiMap时,key和value是需要唯一,如果value重复添加,会报异常,使用inserve返回的不是一个新的集合,而是原集合关联的一个视图:
Exception in thread "main" java.lang.IllegalArgumentException: value already present: log#.log
public static void biMapTest() {
// 使用HashMap
Map<Integer, String> logMap = Maps.newHashMap();
Map<String, Integer> revertMap;
logMap.put(1, "log!.log");
logMap.put(2, "log@.log");
logMap.put(3, "log#.log");
System.out.println("logMap:"+logMap);
revertMap = getInverteMap(logMap);
System.out.println(revertMap.get("log!.log"));
// 使用BiMap
BiMap<Integer, String> biMap = HashBiMap.create();
biMap.put(1, "log!.log");
biMap.put(2, "log@.log");
biMap.put(3, "log#.log");
biMap.put(4, "log#.log");
System.out.println("before:"+biMap);
BiMap<String, Integer> biMap2 = biMap.inverse();
System.out.println("after:"+biMap2);
}
// 反转K,V
public static <K, V> Map<V, K> getInverteMap(Map<K, V> map){
HashMap<V, K> targetMap = Maps.newHashMap();
for (Map.Entry<K, V> entry :map.entrySet()) {
targetMap.put(entry.getValue(), entry.getKey());
}
return targetMap;
}
实现:
HashBiMap
ImmutableBiMap
EnumBiMap
其他实现
Table:
public static void tableTest() {
Table<String, Integer, String> aTable = HashBasedTable.create();
for (char a = 'A'; a<='C'; ++a) {
for(int i=1;i<=3;i++) {
aTable.put(Character.toString(a), i, String.format("%c%d", a,i));
}
}
System.out.println(aTable.column(2));
System.out.println(aTable.row("A"));
System.out.println(aTable.get("B", 1));
System.out.println(aTable.contains("D", 5));
System.out.println(aTable.containsColumn(3));
System.out.println(aTable.containsRow("A"));
System.out.println(aTable.columnMap());
System.out.println(aTable.rowMap());
System.out.println(aTable.remove("A", 1));
System.out.println(aTable.columnMap());
// a 1 a1 b 1 b1 c 1 c1
// a 2 a2 b 2 b2 c 2 c2
// a 3 a3 b 3 b3 c 3 c3
}
输出:
{A=A2, B=B2, C=C2}
{1=A1, 2=A2, 3=A3}
B1
false
true
true
{1={A=A1, B=B1, C=C1}, 2={A=A2, B=B2, C=C2}, 3={A=A3, B=B3, C=C3}}
{A={1=A1, 2=A2, 3=A3}, B={1=B1, 2=B2, 3=B3}, C={1=C1, 2=C2, 3=C3}}
A1
{2={A=A2, B=B2, C=C2}, 3={A=A3, B=B3, C=C3}, 1={B=B1, C=C1}}
该接口主要是对类似于table数据结构的一种实现,
row返回一个非空的Map<C,V>视图,标识一行,修改该视图会影响原数据结构,rowMap返回一个Map<R,Map<C,V>>的视图,rowKeySet返回一个类似于Set
column参考row。
cellSet返回一行,类似于Map.entry,但它是通过行和列区分的。
相关实现:
HashBaseTable
TreeBaseTable
ImmutableTable
ArrayTable: 需要在构建时就确定大小,底层是二维数组,这样可以在数据密集的情况下,提高时间和空间的效率。
ClassToInstanceMap:
提供了类似Map<Class<? extends B>,B>的实现,可以理解为B的子类到B对象的一个映射。
public static void classToInstanceMapTest() {
ClassToInstanceMap<String> classToInstanceMap = MutableClassToInstanceMap.create();
ClassToInstanceMap<Score> classToInstanceMap2 = MutableClassToInstanceMap.create();
classToInstanceMap.put(String.class, "zhangsan");
Score sc = new Score(1, 6);
MathScore src = new MathScore(11, 66);
classToInstanceMap2.put(Score.class, sc);
classToInstanceMap2.put(Score.class, src);
Score sr = classToInstanceMap2.getInstance(Score.class);
System.out.println(sr);
}
RangeSet:
RangeMap:
不常用,省略...
hashings
缓存
缓存就是将数据暂时存储在内存之中,以便下次使用。在日常开发中,由于受到硬盘io性能以及我们本身系统获取和处理数据是可能比较耗时,到对这个数据请求量很大时,频繁的硬盘io和数据逻辑处理就会造成硬盘和cpu的资源瓶颈出现。缓存的作用就是将这些数据存放在内存之中,当客户端或者线程需要相同的数据是,直接从内存之中获取,这样可以提交系统的响应时间,也避免了频繁的对相同的数据进行逻辑处理,这样就提高了系统的性能。
Guava提供了两种创建缓存的方式:
public static void doSomething1() {
try {
// 方式一:使用CacheLoader接口
LoadingCache<String, String> builder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>(){
public String load(String key) throws Exception {
return "hello:"+key;
}
});
// System.out.println(builder.get("kitty"));
// System.out.println(builder.apply("java"));
// builder.put("key", "value");
// System.out.println(builder.get("key"));
// 方式二:使用callable callback
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
String zyg = cache.get("sjk", () -> "http:tcp");
System.out.println(zyg);
zyg = cache.get("paiet", () -> "功夫熊猫");
System.out.println(zyg);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
1、cacheLoader泛型实现
protected static LoadingCache<String, String> loading;
public static <K, V> LoadingCache<K, V> cached(CacheLoader<K, V> loader){
LoadingCache<K , V> cache = CacheBuilder
.newBuilder()
.maximumSize(2)
.weakKeys()
.softValues()
.refreshAfterWrite(120, TimeUnit.SECONDS)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(new RemovalListener<K, V>(){
@Override
public void onRemoval(RemovalNotification<K, V> rn) {
System.out.println(rn.getValue()+"被移除");
}})
.build(loader);
return cache;
}
public static LoadingCache<String, String> commonCache(){
loading = cached(new CacheLoader<String, String>(){
public String load(String key) throws Exception {
return "hello"+key;
}
});
return loading;
}
public static void doSomething2() {
// CacheLoader的泛型实现
loading.put("1", "张三");
loading.apply("pisa");
}
public static void doSomething3() {
// callable callback的泛型实现
LoadingCache<String, String> ld = commonCache();
try {
System.out.println(ld.get("pisa"));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
2、callable callback泛型实现
Cache<String,String> cache;
public static <K,V> Cache<K, V> cached2() {
return CacheBuilder.newBuilder().maximumSize(100)
.expireAfterAccess(10, TimeUnit.MINUTES)
.build();
}
public static String getCacheValue(final String userName) {
try {
return cache.get(userName, new Callable<String>() {
public String call() throws Exception {
System.out.println(userName+"from lbld");
return "hello:"+userName;
}
});
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
public static void callableTest() {
cache = cached2();
System.out.println(getCacheValue("zhangsan"));
}
相关方法说明:
1、大小
maxinumsize(long),weigher(weigher),maxinumweigher(long)
2、时间
expireAfterAccess(long,TimeUtil),expireAfterWriter(long,TimeUtil)
3、引用
weekKeys(),weekValues(),softValues()
4、删除
invalidate(key),invalidateAll(keys),invalidateAll()
5、删除监听器
removelListenter(RemovelListener)
6、过期策略(待思考)
LoadingCache.refresh(key) // 在生成新value的时候,旧的仍可以使用
CacheLoader.load(K,V) // 允许使用
CacheBuilder.refreshAfterWriter(long,TimeUtil) // 自动刷新
数据移除:
1、被动移除
1.1、大小
一般使用的是maxinumsize(long)
size指的是缓存的条目数,不是内存或是其他
不一定刚好达到long的大小,临近就会清除不常用的缓存
如果缓存删除了,使用cacheloader方式,会再次查找一次,没有则报错
1.2、时间
expireAfterAccess(long,TimeUtil) 最后一次操作之后
expireAfterWriter(long,TimeUtil) 使用或修改之后
1.3、引用
取决于虚拟机的垃圾回收机制
2、主动移除
invalidate(key),invalidateAll(keys),invalidateAll()
删除监听器是跟删除同步进行的,如果需要异步,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)。 --未验证
io
refelection
concurrent
EvenBus
事件处理机制,是对事件监听、生产/消费,广播/订阅的一个优雅的解决方案。
基本使用: