Guava 学习

基本工具

optional

null值的问题
map.get(key)== null ;并不知道是没有该值还是整个map是空

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

Optional.of(T):创建指定引用的Optioanl实例,引用为null快速失败

查询api

is present:判断若为非null引用返回true
T get():若引用缺失(null)返回异常
T or(T):若引用缺失返回指定的值
T orNull():若引用缺失返回null
Set<T> asSet:引用存在返回一个只有单一元素的集合,
引用缺失返回空集合

Guava的排序

创建排序器
提供的Ordering类基于Comparator的静态方法实现,提供链式调用定制和增强现有比较器
1.natural():对可排序类型做自然排序,如数字按大小,日期按先后
2.usingToString():按对象的字符串形式做字典排序
3.from(Comparator):把给定的Comparator转换为排序器

Ordering<String> byLengthOrdering = new Ordering<String>() {
public int compare(String left, String right) {
return Ints.compare(left.length(), right.length());
}
}

链式调用方法
1.reverse:获取语义相反的排序器
2.nullsFirst():使用当前排序器,把额外的null值排到最前面
3.nullsLast():使用当前排序器,把额外的null值排到最后面
4.compound(Comparator):合成新的比较器,处理当前排序器中相等的情况
5.lexicographical():基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>的排序器
6.onResultOf(Function):对集合元素中调用Function,再按返回值用当前排序器排序

代码例子

class Foo {
@Nullable String sortedBy;
int notSortedBy;
}

Ordering<Foo> ordering = Ordering.natural().nullsFirst()
.onResultOf(new Function<Foo, String>() {
public String apply(Foo foo) {
return foo.sortedBy;
}
});

链式调用按照从后向前
排序器先调用apply方法获取sortrdBy值,并把sortedBy为null的元素放到最前面,把剩下的元素按sortedBy进行自然排序,(每次链式调用都是用后面的方法包装了前面的排序器)

Guava同样提供可以操纵若干集合或元素值的方法

1.greatestOf(Iterable iterable,int k):获取可迭代对象中最大的k个元素
2.idOrdered(Iterable):判断迭代器中的对象是否已经按照规定排序
3.sortedCopy(Iterable):判断迭代器中的对象是否已经按照规定排序,不允许排序值相等的元素
4.min(E,E,E....)返回参数中最小的哪一个
5.min(Iterable)返回迭代器中最小的元素,如果没有数据抛异常

缓存

实例:缓存的设计方案,看java面试题

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);
}
});

Guava 缓存适用于单个应用运行时的本地缓存,他不把数据存在文件或者外部服务器

加载

1.CacheLoader:以默认的方式加载key - value;
不支持缓存null,如果load调用返回null,则在get时候抛出异常(需要业务处理null)
2.如果没有默认的加载运算,但是要保留get - if absent- compute的原子语义,需要调用get的时候传入callable实例。

CacheLoader

loadingCache 是附带CacheLoader构建而成的缓存实现,创建自己的CacheLoader通常只需要简单的实现V load(key)

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});

...

try {
return graphs.get(key);
} catch (ExecutionException e) {
throw new OtherException(e.getCause());
}

getAll(Iterable<?extends k>)
getAll 方法会单独调用CacheLoader.load来加载缓存,同样可以重载CacheLoader.loadAll来批量加载
或者使用

CacheBuilder.newBuilder().build(CacheLoader.from(this::getDeviceCodeFromDb));

这种方式,直接加载全量数据(从数据库中读取)

Callable

所有的Guava cache 不管有没有自动加载的动能,都是支持get(k,callable),callable使用运算并将结构置于缓存中
该方法实现了如果有缓存就返回,否则运算,缓存,然后返回

    LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
            .expireAfterAccess(10, TimeUnit.MINUTES)
            .build(new CacheLoader<Key, Graph>() {
                @Override
                public Graph load(Key key) throws Exception {
                    return create(key);
                }
            });
    private void test(Key key){
        graphs.get(key, new Callable<Graph>() {
            @Override
            public Graph call() throws Exception {
                return doSomeThing();
            }
        });
    }

显示插入

数据插入缓存可以使用cache.put,或者使用cache.asmap视图提供的方法也能修改缓存,但是asMap修改缓存不能保证修改的缓存被原子的加载到缓存中
结论
相比于cache.asMap.putifAbsent(k,v);cache.get(k,callable)应该总是优先使用

缓存回收

基于容量回收
两个方面
1.基于数量回收:在构建缓存时候使用 maxinumSize(long),当缓存中的数目达到限定之前就可能回收
2.基于权重回收:在构建缓存时候使用 maxinumWeight(long),指定最大的权重数,使用cacheBuilder.weigher(Weigher)创建一个函数用于计算值得权重

基于定时回收
cache.expireAfterAccess(long,TimeUnit):缓存项再给定时间内没有被读写,则回收
cache.expireAfterWrite(long, TimeUnit)缓存项在给定的时间内没有被写访问,则回收

基于引用回收
通过使用weekKeys()弱引用的键,或者weekValues()弱引用的值,或者softValues()软引用的值,guava cache可以把缓存设置为允许垃圾回收

显示清除
个别键清除 cache.invalidate();
批量清除cache.invalidateAll(keys)
清除所有的缓存项目 cache.invalidateAll()

移除监听器
通过cacheBuilder.removalListener(RemovalListener),声明一个监听器
当缓存项被移除时候,RemoveListener会获取通知(RemovalNotifiaction),其中包含移除原因,键,值
默认情况下,监听器方法就是在移除缓存的时候同步的调用,但是同步调用可能影响用户对缓存的请求,所以我们可以将监听器修饰为异步操作
RemovalListener.asynchronous(RemovalLitener,Executor)

刷新
LoadingCache.refresh()刷新表示为键加载新值,这个过程可以是异步的,在刷新的过程中仍然可以返回旧的值,出现异常的时候也会保留旧的值

CacheBuilder.refreshAfterWrite(long,TimeUnit)

为缓存自动添加定时刷新的新功能,和expireAfterWrite相反,refresh可以保持缓存刷新时缓存的可用性
缓存项只有被检索的时候才会进行刷新,同时声明了expire和refresh,如果一直没有检索,如果到时间了,缓存项就会变得可以回收
支持异步刷新
当重写了reload方法会异步的reload,否则默认情况下是同步的

LoadingCache<String,String> loadingCache1=CacheBuilder.newBuilder()  
                   .build(new CacheLoader<String, String>() { 
                     @Override  
                     public ListenableFuture<String> reload(String key, String oldValue) throws Exception {  
                            return refreshPools.submit(new Callable<String>() {  
                               //交给线程池异步处理
                                @Override  
                                public String call() throws Exception {  
                                    return getData(key);  
                                } 
               }  
});

统计
CacheBuidler.recordStats()可以开启缓存的统计时间
hitRate():缓存命中率
avaerageLoadPenalty():加载新值得平均时间
evictionCount():缓存项被回收的总数,不包括显示的清除

asMap视图
asMap提供了缓存的currenthashmap形式,
cache.asMap()包含了所有加载到缓存的项
asMap.getKey,等同于cache.getIFPresent(key)。
所以的asMap的读写操作都会重置相关缓存项的访问时间,包含Cache.asMap.get()/put()

补充参数

1.maximumSize( long ):设置缓存Size 的上限,单位是键值对的个数。
2.concunrrentcyLevel(int ):定义当前缓存所支持的并发级别的上限,Guava提供了设置并发级别的api,使得缓存支持并发的写入和读取。同ConcurrentHashMap类似Guava cache的并发也是通过分离锁实现。在一般情况下,将并发级别设置为服务器cpu核心数是一个比较不错的选择。
3.get() vs getUnchecked()
get(key)会默认从缓存查,如果查询不到则电泳CacheLoader加载,但是cacheLoader会抛出异常,
get会抛出两种异常ExecutionException,或者未检测的异常UncheckedExecutionException
getUnchecked(k) 方法,这个方法会将所有的异常包装在 UncheckedExecutionException 异常中

问题点

refreshAfterWrite:当缓存项上一次更新操作后多久会被刷新。但是不会主动的移除key,只有再有新的请求进来以后才会执行reload,所以有种情况是:在吞吐量较低的情况下(后台在异步刷新,但是当前可以访问,此时访问就有可能是旧的值):解决办法使用:expire 和 refresh 混合使用
举例
.refreshAfterWrite(20, TimeUnit.MINUTES)
.expireAfterWrite(30, TimeUnit.MINUTES)
第一次请求load数据,20分钟内都是读的缓存数据,20分钟以后数据应该刷新了,但是如果一直没有访问就不会进行刷新,然后30分钟之前(20分钟以后)都没有数据进行访问,此时就要进行对key的移除,下次读就是重新加载,但是如果一直有数据访问,那就一直异步刷新key不会进行数据的清理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容

  • Google生产的工具类,目的是简化开发 Optional - 用来表示可能为null的T类型引用(增强null的...
    ZzGo12阅读 397评论 0 0
  • Guava简单介绍 1 资料链接 极客学院http://wiki.jikexueyuan.com/project/...
    田园小丁阅读 1,812评论 0 3
  • 一、接口声明 二、接口方法 ConcurrentMap<K,V> asMap()返回存储在此缓存中的线程安全的键值...
    codeduck1阅读 363评论 0 1
  • com.google.common.cache 1、背景 缓存,在我们日常开发中是必不可少的一种解决性能问题的方法...
    拾壹北阅读 22,135评论 0 25
  • guava cache简介 为什么会有guava cache 实际开发中,有时候会有一些不常修改,但是经常会被用到...
    黄二的NPE阅读 836评论 0 2