Guava工程包含了若干被google的java项目广泛依赖的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [commonannotations] 、字符串处理 [string processing] 、I/O 等等。所有这些工具每天都在被Google的工程师应用在产品服务中。
这些高质量的API可以使你的java代码更加优雅,更加简洁,让你的工作更加轻松愉悦,下面我们来开启Java编程学习之旅。
源码包的简单说明:
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:多线程工具包。
1) 使用和避免null(Optional)
null会引起歧义,会造成让人迷惑的错误,有时也会让人感到不爽。Guava中的许多工具遇到null时,会拒绝或者马上报错,而不是盲目的接受。
鉴于此google的guava库中提供了Optional接口来使null快速失败,即在可能为null的对象上做了一层封装,在使用Optional静态方法of时,如果传入的参数为null就抛出NullPointerException异常。
在Guava中Optional类就是用来强制提醒程序员,注意对Null的判断。
Optional的另外几个方法
Optional<T>.of(T) 为Optional赋值,当T为Null直接抛NullPointException,建议这个方法在调用的时候直接传常量,不要传变量
Optional<T>.fromNullable(T) 为Optional赋值,当T为Null则使用默认值。建议与or方法一起用,风骚无比
Optional<T>.absent() 为Optional赋值,采用默认值
T or(T) 当Optional的值为null时,使用or赋予的值返回。与fromNullable是一对好基友
T get() 当Optional的值为null时,抛出IllegalStateException,返回Optional的值
boolean isPresent() 如果Optional存在值,则返回True
T orNull() 当Optional的值为null时,则返回Null。否则返回Optional的值
Set<T> asSet() 将Optional中的值转为一个Set返回,当然只有一个值啦,或者为空,当值为null时。
使用Optional的意义?
使用Optional除了赋予null语义,增加了可读性,最大的优点在于它一种傻瓜式的防护,Optional迫使你积极思考引用缺失的情况,因为你必须显式地从Optional获取引用。直接使用null很容易让人忘掉某些情形,尽管FindBugs可以帮助查找null相关的问题,但是我们还是认为它并不能准确地定位问题根源。
2) 前提条件(Preconditions)
使方法的条件检查更简单。
Guava在Preconditions类中提供了若干前置条件判断的实用方法,我们强烈建议在Eclipse中静态导入这些方法。每个方法都有三个变种:
a) 没有额外参数:抛出的异常中没有错误消息;
b) 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息;
c) 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象:这个变种处理异常消息的方式有点类似printf,但考虑GWT的兼容性和效率,只支持%s指示符。
例如:查看源代码打印帮助
checkArgument(i>= 0, "Argument was %s but expected nonnegative", i);
checkArgument(i< j, "Expected i < j, but %s > %s", i, j);
方法声明(不包括额外参数)
描述
检查失败时抛出的异常
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
3) 常见的对象方法(Objects)
简化Object方法实现,如hashCode()和toString();
a) equals
当一个对象中的字段可以为null时,实现Object.equals方法会很痛苦,因为不得不分别对它们进行null检查。使用Objects.equal帮助你执行null敏感的equals判断,从而避免抛出NullPointerException。
b) hashCode
用对象的所有字段作散列[hash]运算应当更简单。Guava的Objects.hashCode(Object...)会对传入的字段序列计算出合理的、顺序敏感的散列值。你可以使用Objects.hashCode(field1, field2, …, fieldn)来代替手动计算散列值。
c) toString
好的toString方法在调试时是无价之宝,但是编写toString方法有时候却很痛苦。使用 Objects.toStringHelper可以轻松编写有用的toString方法。
4) 排序
Guava强大的”流畅风格比较器”,具体到下章会介绍到。
5) Throwable类
简化了异常和错误的传播与检查;
guava类库中的Throwables提供了一些异常处理的静态方法,这些方法的从功能上分为两类,一类是帮你抛出异常,另外一类是帮你处理异常。
RuntimeException propagate(Throwable)
如果Throwable是Error或RuntimeException,直接抛出;否则把Throwable包装成RuntimeException抛出。返回类型是RuntimeException,所以你可以像上面说的那样写成throw Throwables.propagate(t),Java编译器会意识到这行代码保证抛出异常。
void propagateIfInstanceOf( Throwable, Class<X extends Exception>) throws X
Throwable类型为X才抛出
void propagateIfPossible( Throwable)
Throwable类型为Error或RuntimeException才抛出
void propagateIfPossible( Throwable, Class<X extends Throwable>) throws X
Throwable类型为X, Error或RuntimeException才抛出
介绍guava对jdk集合类的扩展,包括不可变集合,新集合类型: multisets, multimaps, tables, bidirectional maps等,强大的集合工具类: 提供java.util.Collections中没有的集合工具,扩展工具类:让实现和扩展集合类变得更容易,比如创建Collection的装饰器,或实现迭代器
集合API的使用, 可以简化集合的创建和初始化;
guava API 提供了有用的新的集合类型,协同已经存在的java集合工作的很好。
分别是 MultiMap, MultiSet, Table, BiMap,ClassToInstanceMap
1) google guava的不可变集合
不可变对象有很多优点:
a) 当对象被不可信的库调用时,不可变形式是安全的。
b) 当不可变对象被对个线程调用时,不存在竞态条件问题;
c) 不可变集合不需要考虑变化,因此可以节约时间和空间,所有不可变集合都比可变集合形式有更好的内存利用率(分析和测试细节);
d) 不可变对象因为有固定不变,可以用作常量来安全使用。
总结:数据不可变;不需要同步逻辑;线程安全;自由共享;容易设计和实现;内存和时间高效
创建对象的不可拷贝是一项很好的防御性编程技巧,Guava为所有JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。
JDK也提供了可以将集合变成不可变的方法,Collections.unmodifiableXXX,但是被认为是不好的。
a) 笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;
b) 不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的;
c) 低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。