Guava 项目包含了谷歌在基于 Java 的项目中依赖的几个 Google 核心库:集合,缓存,原语支持,并发库,常见注释,字符串处理,I/O 等。
- 基本工具类:让使用 Java 语言更令人愉悦
- 使用和避免 null:null 有语言歧义, 会产生令人费解的错误, 反正他总是让人不爽。很多 Guava 的工具类在遇到 null 时会直接拒绝或出错,而不是默默地接受他们。
- 前提条件:更容易的对你的方法进行前提条件的测试。
- 常见的对象方法: 简化了 Object 常用方法的实现, 如 hashCode() 和 toString()。
- 排序: Guava 强大的 "fluent Comparator"比较器, 提供多关键字排序。
- Throwable 类: 简化了异常检查和错误传播。
- 集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。
- Immutable collections(不变的集合): 防御性编程, 不可修改的集合,并且提高了效率。
- New collection types(新集合类型):JDK collections 没有的一些集合类型,主要有:multisets,multimaps,tables, bidirectional maps 等等
- Powerful collection utilities(强大的集合工具类): java.util.Collections 中未包含的常用操作工具类
- Extension utilities(扩展工具类):给 Collection 对象添加一个装饰器还是实现迭代器? 我们可以更容易的实现这些。
- 缓存:本地缓存,可以很方便的操作缓存对象,并且支持各种缓存失效行为模式。
- Functional idioms(函数式):简洁, Guava 实现了 Java 的函数式编程,可以显著简化代码。
- Concurrency(并发):强大,简单的抽象,让我们更容易实现简单正确的并发性代码
- ListenableFuture(可监听的 Future): Futures,用于异步完成的回调。
- 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 反射机制工具类。
Preconditions
Preconditions 类提供了一个静态方法列表,用于检查方法或构造函数是否以有效的参数值被调用。如果一个先决条件失败,就会抛出一个定制的异常。Preconditions 类中的每个静态方法都有三个变体:
- 没有参数,抛出的异常没有错误信息。
- 一个额外的 Object 参数作为错误信息。异常会被抛出一个错误信息。
- 一个额外的字符串参数,以及任意数量的额外对象参数作为一个占位符的错误信息。它的行为有点像 printf,但为了 GWT 的兼容性和效率,它只允许使用 %s 指示器
我们来看看如何使用 Preconditions 类。
checkArgument
Preconditions 类的方法 checkArgument 确保传递给调用方法的参数的真实性。该方法接受一个布尔条件,并在条件为假时抛出一个 IllegalArgumentException。我们可以在不向 checkArgument 方法传递任何额外参数的情况下使用 checkArgument:
@Test
public void whenCheckArgumentEvaluatesFalse_throwsException() {
int age = -18;
assertThatThrownBy(() -> Preconditions.checkArgument(age > 0))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(null).hasNoCause();
}Copy to clipboardErrorCopied
我们可以通过传递错误信息从 checkArgument 方法中得到一个有意义的错误信息:
@Test
public void givenErrorMsg_whenCheckArgEvalsFalse_throwsException() {
int age = -18;
String message = "Age can't be zero or less than zero.";
assertThatThrownBy(() -> Preconditions.checkArgument(age > 0, message))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(message).hasNoCause();
}Copy to clipboardErrorCopied
我们可以通过传递一个错误信息,从 checkArgument 方法中得到一个有意义的错误信息以及动态数据:
@Test
public void givenTemplateMsg_whenCheckArgEvalsFalse_throwsException() {
int age = -18;
String message = "Age should be positive number, you supplied %s.";
assertThatThrownBy(
() -> Preconditions.checkArgument(age > 0, message, age))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(message, age).hasNoCause();
}Copy to clipboardErrorCopied
checkElementIndex
方法 checkElementIndex 检查一个索引是否是列表、字符串或指定大小的数组中的有效索引。元素索引的范围可以从 0 到大小不等。你不需要直接传递一个 list、字符串或数组,你只需要传递它的大小。如果索引不是有效的元素索引,这个方法就会抛出 IndexOutOfBoundsException,否则就会返回一个正在传递给方法的索引。
让我们看看如何使用这个方法,通过在检查 ElementIndex 方法抛出异常时传递一个错误信息来显示它的有意义的错误信息:
@Test
public void givenArrayAndMsg_whenCheckElementEvalsFalse_throwsException() {
int[] numbers = { 1, 2, 3, 4, 5 };
String message = "Please check the bound of an array and retry";
assertThatThrownBy(() ->
Preconditions.checkElementIndex(6, numbers.length - 1, message))
.isInstanceOf(IndexOutOfBoundsException.class)
.hasMessageStartingWith(message).hasNoCause();
}Copy to clipboardErrorCopied
checkNotNull
方法 checkNotNull 检查作为参数提供的值是否为空。它返回被检查的值。如果传递给这个方法的值是空的,那么就会抛出一个 NullPointerException。接下来,我们将展示如何使用这个方法,通过传递错误信息,从 checkNotNull 方法中获取有意义的错误信息:
@Test
public void givenNullString_whenCheckNotNullWithMessage_throwsException () {
String nullObject = null;
String message = "Please check the Object supplied, its null!";
assertThatThrownBy(() -> Preconditions.checkNotNull(nullObject, message))
.isInstanceOf(NullPointerException.class)
.hasMessage(message).hasNoCause();
}Copy to clipboardErrorCopied
我们还可以通过向错误信息传递一个参数,从 checkNotNull 方法中得到一个基于动态数据的有意义的错误信息:
@Test
public void whenCheckNotNullWithTemplateMessage_throwsException() {
String nullObject = null;
String message = "Please check the Object supplied, its %s!";
assertThatThrownBy(
() -> Preconditions.checkNotNull(nullObject, message,
new Object[] { null }))
.isInstanceOf(NullPointerException.class)
.hasMessage(message, nullObject).hasNoCause();
}Copy to clipboardErrorCopied
checkPositionIndex
方法 checkPositionIndex 检查作为参数传递给本方法的索引是否是指定大小的列表、字符串或数组中的有效索引。一个位置索引的范围可以从 0(含)到大小(含)。你不需要直接传递列表、字符串或数组,你只需要传递它的大小。
如果传递的索引不在 0 和给定的大小之间,这个方法就会抛出一个 IndexOutOfBoundsException,否则就会返回索引值。让我们看看如何从 checkPositionIndex 方法中得到有意义的错误信息。
@Test
public void givenArrayAndMsg_whenCheckPositionEvalsFalse_throwsException() {
int[] numbers = { 1, 2, 3, 4, 5 };
String message = "Please check the bound of an array and retry";
assertThatThrownBy(
() -> Preconditions.checkPositionIndex(6, numbers.length - 1, message))
.isInstanceOf(IndexOutOfBoundsException.class)
.hasMessageStartingWith(message).hasNoCause();
}Copy to clipboardErrorCopied
checkState
方法 checkState 检查对象状态的有效性,并且不依赖于方法的参数。例如,一个 Iterator 可能会使用这个方法来检查在调用 remove 之前是否已经调用了 next。如果对象的状态(作为方法参数传递的布尔值)处于无效状态,该方法会抛出一个 IllegalStateException。
让我们看看如何使用这个方法,通过在 checkState 方法抛出异常时传递一个错误信息来显示它的有意义的错误信息。
@Test
public void givenStatesAndMsg_whenCheckStateEvalsFalse_throwsException() {
int[] validStates = { -1, 0, 1 };
int givenState = 10;
String message = "You have entered an invalid state";
assertThatThrownBy(
() -> Preconditions.checkState(
Arrays.binarySearch(validStates, givenState) > 0, message))
.isInstanceOf(IllegalStateException.class)
.hasMessageStartingWith(message).hasNoCause();
}