如何使用guava maven的缓存管理

Guava缓存器源码分析——数据查询 - CSDN博客
Guava缓存器的数据查询函数调用:
&&&&get(K) ——
&&&&&&&&&&&localCache.getOrLoad(key) ——&
&&&&&&&&&&&&& & & &get(key, defaultLoader)(如果创建的为Cache缓存,defaultLoader设为null)
具体步骤:
1、计算key的哈希值。
& & & LocalCache会使用分段锁来保护不同段的数据,在查询或插入元素时,需要通过哈希算法定位到Segment,&LocalCache&会使用变种Hash算法Wang/Jenkins&对元素的hashCode进行一次再哈希 :
 static int rehash(int h)& {
& & &&&&h += (h && 15) ^ 0xffffcd7d;
& &&&&& h ^= (h &&& 10);
& &&&&& h += (h && 3);
& &&&&& h ^= (h &&& 6);
& &&&&& h += (h && 2) + (h && 14);
& &&&&& return h ^ (h &&& 16);
  再哈希的目的是为了减少哈希冲突,使元素能够比较均匀的分布在不同的Segment上,从而提高缓存器的存取效率。如果哈希的质量太差,元素集中哈希到少数Segment中,不仅存取元素缓慢,分段锁也会失去意义。
2、通过哈希值,获取数据段。
& & &segments[(hash &&& segmentShift) & segmentMask]
& & & 下面分析下初始化segmentShift、segmentMask及segments的代码:
& &&&&& & & &//缓存器支持的最大段数MAX_SEGMENTS&为1 && 16,如果在builder中没有设置concurrencyLevel的大小,默认为4。
& & & & & & &concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);
& & & & & & &//一般计算出一个大于或等于concurrencyLevel的最小的2的N次方值来作为segments数组的长度,如果设置了maxWeight,segmentCount 还需满足segmentCount &* 20 &= maxWeight&,此时假设每个段平均哈希到20个元素,再少就不继续增加段了:
&&&&&&&&&&&&&int segmentShift = 0;
& &&&&&&&&& &int segmentCount = 1;
& & &&&&& & &while (segmentCount & concurrencyLevel
& & & & &&&&&&&&& &&& (!evictsBySize() || segmentCount * 20 &= maxWeight)) {
& & & &&&&&&&&& & &++segmentS
& & &&&&&&&&&& & & segmentCount &&= 1;
& & &&&&& & &}
&&&&&&&&& & &this.segmentShift = 32 - segmentS
& &&&&&&&&& &segmentMask = segmentCount - 1;
& &&&&&&&&&& this.segments = newSegmentArray(segmentCount);
& & &假如concurrencyLevel等于14或15, segmentCount 等于16,则缓存器里锁的个数也是16。
3、调用数据段的get方法。
&&&&&V get(K key, int hash, CacheLoader&? super K, V& loader)
& & &1)获取键值的引用: ReferenceEntry&K, V& e = getEntry(key, hash);
& & & & & &获取值:V value = getLiveValue(e, now);
& & & & & &其中判断数据是否过期的方法:
&&&&&&&&& &&boolean isExpired(ReferenceEntry&K, V& entry, long now) {
& & &&&&&&&&&&&&checkNotNull(entry);
& &&&&&&&&&&&&& if (expiresAfterAccess()
& & & & &&&&&&&&&&&&&& (now - entry.getAccessTime() &= expireAfterAccessNanos)) {
& & & &&&&&&&&&&&&&&&&
& &&&&&&&&&&&&& }
& &&&&&&&&&&&&& if (expiresAfterWrite()
& & & &&&&&&&&&&&&& && (now - entry.getWriteTime() &= expireAfterWriteNanos)) {
& & & &&&&&&&&&&&&
& &&&&&&&&&&&&& }
& &&&&&&&&&&&&&
& &&&&&&&&}
& & & & & 如果获取的值不为空,则需要将此次访问加入到访问队列(Queue&ReferenceEntry&K, V&&)中,当缓存器满时,用来选择需要清出的数据,同时记录命中信息。
& & & & & 如果获取的值正在加载(valueReference.isLoading()),则需等待其加载完后返回。
& & &2)键值引用为空,则需要加载。
& & & & & lockedGetOrLoad(key, hash, loader);
& & & & & 数据的加载过程会上ReentrantLock锁(Segment继承至ReentrantLock),同时会重新进行验证:如果缓存值正在加载,则无需进行下一步操作;若果缓存值没在加载,且缓存值已存在于缓存且没有过期,则返回该值;验证完才开始同步加载。
& & &Guava缓存器将缓存数据分为一个个段,每个段中的数据实际存放在volatile AtomicReferenceArray&ReferenceEntry&K, V&& table中, ReferenceEntry接口中定义了许多与键值相关的函数,比如获取访问时间、写时间、键、值等, Guava缓存器在数据查询时,考虑得很全面,以后遇到多线程环境下数据读写的问题,可以借鉴这里面的思想。&Guava库学习:学习Guava Cache(一)MapMaker
20:36:19.0
& & 在软件开发中,Cache缓存技术一直是非常重要的主题,不管我们正在进行任何简单的编程工作,我们总能在编程过程中找到一些缓存机制,即使是你使用一个Map获取静态的值,它也是缓存的一种形式,但我们大多数人并不清楚其中的缓存使用。Guava Cache为我们提供了相比于简单的HashMap更强大和灵活的缓存机制,并不像Ehcache和Memcache那样具有健壮性。在本系列的学习中,我们将学习Guava提供的缓存机制,首先我们学习Guava Cache(一)MapMaker。
& & 我们可以在mon.collect包下面找到MapMaker类,那么问题来了,我们为什么不在中学习,尽管我们可能已经在Collections的学习中提到了MapMaker,本篇中,我们将MapMaker作为一个提供最基本缓存功能的类进行学习,MapMaker类使用了流畅的接口API,允许我们快速的构造ConcurrentHashMap,我们来看下面的例子:
ConcurrentMap&String, Book& books = new
MapMaker().concurrencyLevel(2)
.softValues()
.makeMap();
& & 上面的例子中,我们构造了一个ConcurrentHashMap,使用String类型作为key,使用Book对象作为value值,通过对ConcurrentHashMap声明的泛型进行指定,我们首先调用了concurrencyLevel()方法,设置了我们允许在map中并发修改的数量,我们还指定了softValues()方法,这样map中的value值都包裹在一个SoftReference(软引用)对象中,可以在内存过低的时候被当作垃圾回收。
& & 其他我们可以指定的方法还包括:weakKeys()和weakValues(),但是MapMaker没有提供softKeys(),当我们给keys或values使用WeakReferences(弱引用)或SoftReference(软引用)时,如果键值的其中一个被当做垃圾回收,整个键值对就会从map中移除,剩余的部分并不会暴露给客户端。
& & 最后值得注意的一点:MapMaker中的softValues()方法在最近的几个guava版本中,已经被标注为Deprecated,MapMaker中的缓存机制已经被移动到mon.cache.CacheBuilder中,MapMaker中的softValues()方法也已经被替换为mon.cache.CacheBuilder#softValues,CacheBuilder的实现是来自MapMaker分支的一个简单增强版API。
提醒:欢迎关注,点击此窗口。今日开源介绍:Google Guava、Google Guice、Joda-Time - 沙漠绿树 - ITeye技术网站
博客分类:
一、Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, 等等. 这些高质量的 API 可以使你的JAVa代码更加优雅,更加简洁,让你工作更加轻松愉悦。下面我们就开启优雅Java编程学习之旅!
  项目相关信息:
  官方首页:  官方下载:  官方文档:
  源码包的简单说明:   mon.annotations:普通注解类型。   mon.base:基本工具类库和接口。   mon.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。   mon.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。   mon.eventbus:发布订阅风格的事件总线。   mon.hash: 哈希工具包。   mon.io:I/O工具包。   mon.math:原始算术类型和超大数的运算工具包。   mon.net:网络工具包。   mon.primitives:八种原始类型和无符号类型的静态工具包。   mon.reflect:反射工具包。   mon.util.concurrent:多线程工具包。
  类库使用手册:
基本工具类:让使用Java语言更令人愉悦。
  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 反射机制工具类。
二、Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC)。Guice非常小而且快。Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数的任意方法,而不仅仅是setter方法)进行注入。Guice还具有一些可选的特性比如:自定义scopes,传递依赖,静态属性注入,与Spring集成和AOP联盟方法注入等。一部分人认为,Guice可以完全替代spring, 因为对于DI组件框架来说, 性能是很重要的, guice比spring快十倍左右, 另外, 也是最重要的一点, 使用spring很容易写成service locator的风格, 而用guice, 你会很自然的形成DI风格.甚至说,guice简单超轻量级的DI框架效率是spring的1.6倍,Spring使用XML使用将类与类之间的关系隔离到xml中,由容器负责注入被调用的对象,而guice将类与类之间的关系隔离到Module中,声明何处需要注入,由容器根据Module里的描述,注入被调用的对象,使用Annotation使用支持自定义Annotation标注,对于相同的接口定义的对象引用,为它们标注上不同的自定义Annotation注释,就可以达到同一个类里边的同一个接口的引用,注射给不同的实现,在Module里用标注做区分,灵活性大大增加。
Guice与Spring的对比使用XML
Spring 使用将类与类之间的关系隔离到xml中,由容器负责注入被调用的对象,因此叫做依赖注入。
Guice 不使用xml,将类与类之间的关系隔离到Module中,声名何处需要注入,由容器根据Module里的描述,注入被调用的对象。使用Annotation
Guice 使用,支持自定义Annotation标注,使用Annotation也未必是好事,范型等新特性也未必是好事,目前大多的服务器均不支持jdk1.5,wls要9以前才支持,而目前的客户由于价格原因也很少选用wls9的,至少我们做过的项目中都没有。功能再强,客户不需要,何用?运行效率
Spring 装载spring配置文件时,需解析xml,效率低,getBean效率也不高,不过使用环境不会涉及到getBean,只有生产环境的时候会用到getBean,在装载spring应用程序的时候,已经完成全部的注射,所以这个低效率的问题不是问题。
Guice 使用Annotation,cglib, 效率高与spring最明显的一个区别,spring是在装载spring配置文件的时候把该注入的地方都注入完,而Guice呢,则是在使用的时候去注射,运行效率和灵活性高。类耦合度
Spring 耦合度低,强调类非侵入,以外部化的方式处理依赖关系,类里边是很干净的,在配置文件里做文章,对类的依赖性极低。
Guice 高,代码级的标注,DI标记@inject侵入代码中,耦合到了类层面上来,何止侵入,简直侵略,代码耦合了过多guice的东西,大大背离了依赖注入的初衷,对于代码的可维护性,可读性均不利。类编写时
Spring 需要编写xml,配置Bean,配置注入。
Guice 只需声明为@inject,等着被注入,最后在统一的Module里声明注入方式。仅支持IOC
Spring 否,spring目前已经涉猎很多部分。
Guice 是,目前仅仅是个DI容器。是否易于代码重构
Spring 统一的xml配置入口,更改容易。
Guice 配置工作是在Module里进行,和spring异曲同功支持多种注入方式
Spring 构造器,setter方法。
Guice Field,构造器,setter方法。灵活性
Guice 1.如果同一个接口定义的引用需要注入不同的实现,就要编写不同的Module,烦琐 2.动态注入,如果你想注射的一个实现,你还未知呢,怎么办呢,spring是没办法,事先在配置文件里写死的,而Guice就可以做到,就是说我想注射的这个对象我还不知道注射给谁呢,是在运行时才能得到的的这个接口的实现,所以这就大大提高了依赖注射的灵活性,动态注射。与现有框架集成度
Spring 1.高,众多现有优秀的框架(如struts1.x等)均提供了spring的集成入口,而且spring已经不仅仅是依赖注入,包括众多方面。2. Spring也提供了对Hibernate等的集成,可大大简化开发难度。3.提供对于orm,rmi,webservice等等接口众多,体系庞大。
Guice 1.可以与现有框架集成,不过仅仅依靠一个效率稍高的DI,就想取代spring的地位,有点难度。配置复杂度
Spring 在xml中定位类与类之间的关系,难度低。
Guice 代码级定位类与类之间的关系,难度稍高。
三、Joda-Time 令时间和日期值变得易于管理、操作和理解。事实上,易于使用是 Joda 的主要设计目标。其他目标包括可扩展性、完整的特性集以及对多种日历系统的支持。并且 Joda 与 JDK 是百分之百可互操作的,因此您无需替换所有 Java 代码,只需要替换执行日期/时间计算的那部分代码。
为什么要使用 Joda?考虑创建一个用时间表示的某个随意的时刻 — 比如,2000 年 1 月 1 日 0 时 0 分。我如何创建一个用时间表示这个瞬间的 JDK 对象?使用 java.util.Date?事实上这是行不通的,因为自 JDK 1.1 之后的每个 Java 版本的 Javadoc 都声明应当使用 java.util.Calendar。Date 中不赞成使用的构造函数的数量严重限制了您创建此类对象的途径。然而,Date 确实有一个构造函数,您可以用来创建用时间表示某个瞬间的对象(除 “现在” 以外)。该方法使用距离 1970 年 1 月 1 日子时格林威治标准时间(也称为 epoch)以来的毫秒数作为一个参数,对时区进行校正。考虑到 Y2K 对软件开发企业的重要性,您可能会认为我已经记住了这个值 — 但是我没有。Date 也不过如此。那么 Calendar 又如何呢?我将使用下面的方式创建必需的实例:Calendar calendar = Calendar.getInstance();calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
使用 Joda,代码应该类似如下所示:DateTime dateTime = new DateTime(, 0, 0, 0, 0);
这一行简单代码没有太大的区别。但是现在我将使问题稍微复杂化。假设我希望在这个日期上加上 90 天并输出结果。使用 JDK,我需要使用清单 1 中的代码:
清单 1. 以 JDK 的方式向某一个瞬间加上 90 天并输出结果
Calendar calendar = Calendar.getInstance();calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);SimpleDateFormat sdf = new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS");calendar.add(Calendar.DAY_OF_MONTH, 90);System.out.println(sdf.format(calendar.getTime()));
使用 Joda,代码如清单 2 所示:
清单 2. 以 Joda 的方式向某一个瞬间加上 90 天并输出结果
DateTime dateTime = new DateTime(, 0, 0, 0, 0);System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS");
两者之间的差距拉大了(Joda 用了两行代码,JDK 则是 5 行代码)。现在假设我希望输出这样一个日期:距离 Y2K 45 天之后的某天在下一个月的当前周的最后一天的日期。坦白地说,我甚至不想使用 Calendar 处理这个问题。使用 JDK 实在太痛苦了,即使是简单的日期计算,比如上面这个计算。正是多年前的这样一个时刻,我第一次领略到 Joda-Time 的强大。使用 Joda,用于计算的代码如清单 3 所示:
清单 3. 改用 Joda
DateTime dateTime = new DateTime(, 0, 0, 0, 0);System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
.withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");
清单 3 的输出为:Sun 03/19/:00.000
如果您正在寻找一种易于使用的方式替代 JDK 日期处理,那么您真的应该考虑 Joda。如果不是这样的话,那么继续痛苦地使用 Calendar 完成所有日期计算吧。当您做到这一点后,您完全可以做到使用几把剪刀修建草坪并使用一把旧牙刷清洗您的汽车。Joda 和 JDK 互操作性JDK Calendar 类缺乏可用性,这一点很快就能体会到,而 Joda 弥补了这一不足。Joda 的设计者还做出了一个决定,我认为这是它取得成功的构建:JDK 互操作性。Joda 的类能够生成(但是,正如您将看到的一样,有时会采用一种比较迂回的方式)java.util.Date 的实例(和 Calendar)。这使您能够保留现有的依赖 JDK 的代码,但是又能够使用 Joda 处理复杂的日期/时间计算。例如,完成 清单 3 中的计算后。我只需要做出如清单 4 所示的更改就可以返回到 JDK 中:
清单 4. 将 Joda 计算结果插入到 JDK 对象中
Calendar calendar = Calendar.getInstance();DateTime dateTime = new DateTime(, 0, 0, 0, 0);System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek().withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");calendar.setTime(dateTime.toDate());
就是这么简单。我完成了计算,但是可以继续在 JDK 对象中处理结果。这是 Joda 的一个非常棒的特性。
Joda 的关键日期/时间概念Joda 使用以下概念,它们可以应用到任何日期/时间库:不可变性(Immutability)、瞬间性(Instant)、局部性(Partial)、年表(Chronology)、时区(Time zone)。我将针对 Joda 依次讨论每一个概念。不可变性
我在本文讨论的 Joda 类具有不可变性,因此它们的实例无法被修改。(不可变类的一个优点就是它们是线程安全的)。我将向您展示的用于处理日期计算的 API 方法全部返回一个对应 Joda 类的新实例,同时保持原始实例不变。当您通过一个 API 方法操作 Joda 类时,您必须捕捉该方法的返回值,因为您正在处理的实例不能被修改。您可能对这种模式很熟悉;比如,这正是 java.lang.String 的各种操作方法的工作方式。瞬间性
Instant 表示时间上的某个精确的时刻,使用从 epoch 开始计算的毫秒表示。这一定义与 JDK 相同,这就是为什么任何 Joda Instant 子类都可以与 JDK Date 和 Calendar 类兼容的原因。更通用一点的定义是:一个瞬间 就是指时间线上只出现一次且唯一的一个时间点,并且这种日期结构只能以一种有意义的方式出现一次。局部性
一个局部时间,正如我将在本文中将其称为局部时间片段一样,它指的是时间的一部分片段。瞬间性指定了与 epoch 相对的时间上的一个精确时刻,与此相反,局部时间片段指的是在时间上可以来回 “移动” 的一个时刻,这样它便可以应用于多个实例。比如,6 月 2 日 可以应用于任意一年的 6 月份(使用 Gregorian 日历)的第二天的任意瞬间。同样,11:06 p.m. 可以应用于任意一年的任意一天,并且每天只能使用一次。即使它们没有指定一个时间上的精确时刻,局部时间片段仍然是有用的。我喜欢将局部时间片段看作一个重复周期中的一点,这样的话,如果我正在考虑的日期构建可以以一种有意义的方式出现多次(即重复的),那么它就是一个局部时间。年表
Joda 本质 — 以及其设计核心 — 的关键就是年表(它的含义由一个同名抽象类捕捉)。从根本上讲,年表是一种日历系统 — 一种计算时间的特殊方式 — 并且是一种在其中执行日历算法的框架。受 Joda 支持的年表的例子包括:ISO(默认)、Coptic、Julian、Islamic。Joda-Time 1.6 支持 8 种年表,每一种都可以作为特定日历系统的计算引擎。时区
时区是值一个相对于英国格林威治的地理位置,用于计算时间。要了解事件发生的精确时间,还必须知道发生此事件的位置。任何严格的时间计算都必须涉及时区(或相对于 GMT),除非在同一个时区内发生了相对时间计算(即时这样时区也很重要,如果事件对于位于另一个时区的各方存在利益关系的话)。DateTimeZone 是 Joda 库用于封装位置概念的类。许多日期和时间计算都可以在不涉及时区的情况下完成,但是仍然需要了解 DateTimeZone 如何影响 Joda 的操作。默认时间,即从运行代码的机器的系统时钟检索到的时间,在大部分情况下被使用。
四、Joda 实际上是涵盖众多用于 Java 语言的替代 API 的大型项目,因此从技术上讲,使用 Joda 和 Joda-Time 名称表示相同的意思是一种误称。但在撰写本文之际,Joda-Time API 目前似乎是唯一处于活跃开发状态下的 Joda API。考虑到 Joda 大型项目的当前状态,我想将 Joda-Time 简称为 Joda 应该没什么问题。官网还在更新中,她目前包含以下的替代API(具体我没有使用过,Google的Guava有相同的工具API):
- Basic types for Date and Time
- Basic types for Money
- Next generation JavaBeans
- String to Object conversion
- Additional collection data structures
- Primitive collections
浏览: 129730 次
来自: 深圳
能提供一下源码做测试吗
当然我把快捷键设成了Eclipse的。 谁能给个我用idea默 ...
我用了10年的Eclipse, 自从接触 android st ...
各位争论都有到。每个人的爱好,习惯不同。每个工具都有偏重,了解 ...
bit1129 写道Idea除了对Maven支持,Eclips ...Google Guava的5个鲜为人知的特性
查看: 247|
评论: 0|原作者: |来自:
摘要: 它是最流行的开源库之一,你应该听过它的大名,它诞生的地方正是人们举办真正的魁地奇比赛的地方(起码实习期内是这样的)。它虽然不是来自哈利波特中的霍格沃兹学校,但却有着自己的专属魔力:Google Guava库包含着 ...
Google Guava有哪些比较冷门但却又实用的特性呢?它是最流行的开源库之一,你应该听过它的大名,它诞生的地方正是人们举办真正的魁地奇比赛的地方(起码内是这样的)。它虽然不是来自哈利波特中的霍格沃兹学校,但却有着自己的专属魔力:Google Guava库包含着许多诞生于Google的核心Java库,这些都是公开发布后在生产环境经历过了各种检验的。它就已经包含Optional了。致力于提升常见任务的开发效率,通过它所提供的功能,开发人员能够高效地完成更优质且更干净的代码。最著名的莫过于它里面的集合库和缓存库了。然而,它的很多非常实用的功能却鲜为人知。说到集合和缓存,Guava库对JDK中的集合API进行了改进,同时它还填补了才最终发布的JCache的空缺()。本文我和大家分享的是在Takipi里面我们所用到的一些Google Guava的特性,以及我们的一些有趣的发现。注意:Guava支持Java 6及以上的版本。1. 无符号基础类型:它们真的存在!Java 8中一个不太为人所知的特性就是它为无符号基础类型所提供的新的解决方案。但更加不为人所知的是在Java 8发布很久之前Guava库就已经有了这个功能了,目前在Java 6及以后的版本中均能使用。我们来看下Guava是如何解决这个问题的。现在在我们面前有两种选择,到底使用哪种最好保持一致:直接将基础类型当int来使用,但要记清楚它可是无符号的:int notReallyInt = UnsignedInts.parseUnsignedInt(); // Max unsigned int String maxUnsigned = UnsignedInts.toString(notReallyInt); // We’re legit!UnsignedInts与UnsignedLongs还支持compare, divide, min, max等方法。你还可以使用包装类型,这样能避免直接使用基础类型容易带来的混淆:UnsignedInteger newType = UnsignedInteger.valueOf(maxUnsigned); newType = newType.plus(UnsignedInteger.valueOf("1")); // IncrementUnsignedInts与UnsignedLongs还支持minus, times, dividedBy以及mod方法。2. 哈希:128位的MurmurHash看一下Java标准库中的非加密哈希算法你会发现少了,这是一个简单高效且还是分布式的算法,在许多语言中都有着很好的支持。我们并不是说要用它来取代Java的hashCode方法,不过如果你想要生成大量的哈希值而32位已经不够用了,但又希望能有一个高效而不会影响到性能的算法,那肯定就是它了。下面是Guava中的实现:HashFunction hf = Hashing.murmur3_128(); // 32bit version available as wellHashCode hc = hf.newHasher()
.putLong(id)
.putString(name, Charsets.UTF_8)
.putObject(person, personFunnel)
你可以使用Funnel来对对象进行分解,里面包含了用于读取对象的指令,假设我们有一个带ID,名字以及出生年份的Person对象:Funnel&Person& personFunnel = new Funnel&Person&() {
public void funnel(Person person, PrimitiveSink into) {
.putInt(person.id)
.putString(person.firstName, Charsets.UTF_8)
.putString(person.lastName, Charsets.UTF_8)
.putInt(birthYear);
}};3. InternetDomainName:用它来取代你的域名校验器Guava还有一个很酷的功能就是它的InternetDomainName,用它来解析及修改域名简直是得心应手。如果你自己写过类似的功能的话,你就会知道它提供的方式是多高效优雅了。它是Mozilla基金会发起的项目,遵循最新的RFC规范,它采用的是中的域名列表。与apache-common库中的竞争者相比,它还提供了许多专门的方法。我们来看一个简单的例子:InternetDomainName owner =
InternetDomainName.from("").topPrivateDomain(); //
InternetDomainName.isValid(“takipi.monsters"); // returns false关于域名有几个概念是比较容易混淆的:publicSuffix()返回的是对应着公共后缀列表中的独立实体的顶级域名。因此返回的可能会有co.uk, .com, .cool这样的结果(没错,.cool是一个真实的后缀,比如, scalais.cool以及cppis.cool)。而topPrivateDomain(),这是对应公共后缀列表的一个独立实体的私有域名。在上调用这个方法会返回,但如果你把它用于某个github主页,比如username.github.io的话则会返回username.github.io,因为这在PSL上是一个单独的实体。当你需要校验域名的时候这个功能就派上用场了,比如我们最近给将JIRA集成进Takipi的时候,首先我们要检查你的JIRA域名,然后才能连接到Takipi的生产环境的错误分析工具中。4. ClassPath反射:魔镜,魔镜看一下Java的反射机制,也就是它的查看自身代码的能力,你会发现,要想列出所在包或者项目中的所有类可不是一件简单的事情。这是Guava中我们非常喜欢的一个特性,它还能获取当前运行环境的许多相关信息。使用起来非常简单:ClassPath classpath = ClassPath.from(classloader);for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses("com.mycomp.mypackage")) {
System.out.println(classInfo.getName());}这段代码会遍历你指定包中的所有类并打印出它们的名字。这里要说明的是它只会扫描我们指定的包的物理路径下的类。如果类是从其它地方加载进来的则不在此列,因此使用它的时候请务必小心,不然你得到的结果就是错误的了。5: CharMatcher:简化版正则?我们用一个你肯定会碰到过的问题来结束这最后一个特性。假设你有一个字符串,或者许多字符串,你希望对它们进行格式化,比如删除空格或者别的字符,替换某个字符等等。总的来说,就是提取匹配某个模式的字符然后进行某个操作。Guava提供了CharMatcher,使得这类问题的处理更得更加优雅。对于这类任务,库里有许多预定义好的模式,比如JAVAUPPERCASE(大写字符),JAVA_DIGIT(数字),INVISIBLE(不可见UNICODE字符)等。除了这些预定义的模式外,你还可以创建自己想要的模式。我们用一段简短的示例来看下它是如何使用的:String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ‘ ‘);它会截取掉字符串末尾的空格并将中间连续的空格合并成一个。String keepAlex = CharMatcher.anyOf(“alex”).retainFrom(someOtherString);而这行会将一个字符串中我的名字里没有的字符都去掉。如果我是一名说唱歌手的话,这将是我的歌曲扬名之时。结论这里我们介绍了Google Guava库中的一些非常有趣的特性,当然了,不包括家喻户晓的集合库以及缓存库。这里面有些功能是在Takipi中广泛用到的,而有些功能是我们觉得比较实用,相信许多项目都能从中受益的。Google Guava库让开发人员变得更加高效,而这也正是我们Takipi所开发的工具想要实现的目标(它可是相当酷的,)我们很想知道你用过的哪个Guava特性是别人可能不太会用到的?(集合和缓存当然不算!)请在下方的评论中分享给大家吧。
上一篇:下一篇:
快毕业了,没工作经验,
找份工作好难啊?
赶紧去人才芯片公司磨练吧!!

我要回帖

更多关于 guava 使用 的文章

 

随机推荐