├── LICENSE
├── README.md
└── articles
├── basic-utilities
├── common-object-methods.md
├── preconditions.md
├── throwable.md
├── user-guide.md
└── using-and-avoiding-null.md
├── caches
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── collections
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── concurrency
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── event-bus
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── functional-idioms
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── graphs
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── hashing
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── io
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── math
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── primitives
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── ranges
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
├── reflection
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
└── strings
├── about-null.md
├── common-object-methods.md
├── preconditions.md
├── throwable.md
└── user-guide.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Charies Gavin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | 
4 |
5 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
6 |
7 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
8 | - 使用和避免 null[[Using and avoiding null](https://github.com/guobinhit/guava-guide/blob/master/articles/basic-utilities/using-and-avoiding-null.md)]:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
9 | - 前置条件[[Preconditons](https://github.com/guobinhit/guava-guide/blob/master/articles/basic-utilities/preconditions.md)]:让你的方法更容易进行前置条件的检查。
10 | - 通用 object 方法[[Common object methods](https://github.com/guobinhit/guava-guide/blob/master/articles/basic-utilities/common-object-methods.md)]:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
11 | - 排序[[Ordering](https://github.com/google/guava/wiki/OrderingExplained)]:Guava 有强大且流畅的`Comparator`类。
12 | - 可抛的[[Throwable](https://github.com/guobinhit/guava-guide/blob/master/articles/basic-utilities/throwable.md)]:简化了异常和错误的检查及传播机制。
13 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
14 | - 不可变集合[[Immutable Collections](https://github.com/google/guava/wiki/ImmutableCollectionsExplained)]:为了进行防御性编程、使用常量集合和提高效率。
15 | - 新集合类型[[New Collection Types]](https://github.com/google/guava/wiki/NewCollectionTypesExplained)]:提供了多集合、多 Map、多表、双向 Map 等。
16 | - 强大的集合工具类[[Powerful Collection Utilities]](https://github.com/google/guava/wiki/CollectionUtilitiesExplained)]:普通的操作并没有在`java.util.Collections`中提供。
17 | - 扩展工具类[[Extension Utilities]](https://github.com/google/guava/wiki/CollectionHelpersExplained)]:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
18 |
19 | - **图[[Graphs](https://github.com/google/guava/wiki/GraphsExplained)]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
20 | - 图[[Graph](https://github.com/google/guava/wiki/GraphsExplained#graph)]:图的边缘是没有自己标识和信息的匿名实体。
21 | - 值图[[ValueGraph](https://github.com/google/guava/wiki/GraphsExplained#valuegraph)]:图的边缘关联着非唯一的值。
22 | - 网络[[Network](https://github.com/google/guava/wiki/GraphsExplained#network)]:图的边缘是唯一的对象。
23 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
24 |
25 | - **缓存[[Caches](https://github.com/google/guava/wiki/CachesExplained)]**:支持本地缓存,也支持多种缓存过期行为。
26 |
27 | - **函数风格[[Functional idioms](https://github.com/google/guava/wiki/FunctionalExplained)]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
28 |
29 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
30 | - [ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained): Future,结束时触发回调 。
31 | - [Service](https://github.com/google/guava/wiki/ServiceExplained):开启和关闭服务,帮助我们处理困难的状态逻辑。
32 |
33 | - **字符串[[Strings](https://github.com/google/guava/wiki/StringsExplained)]**:非常有用的字符串处理工具,包括分割、拼接等等。
34 |
35 | - **原生类型[[Primitives](https://github.com/google/guava/wiki/PrimitivesExplained)]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
36 |
37 | - **区间[[Ranges](https://github.com/google/guava/wiki/RangesExplained)]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
38 |
39 | - **输入输出流[[I/O](https://github.com/google/guava/wiki/IOExplained)]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
40 |
41 | - **散列[[Hashing](https://github.com/google/guava/wiki/HashingExplained)]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
42 |
43 | - **事件总线[[EventBus](https://github.com/google/guava/wiki/EventBusExplained)]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
44 |
45 | - **数学运算[[Math](https://github.com/google/guava/wiki/MathExplained)]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
46 |
47 | - **反射[[Reflection](https://github.com/google/guava/wiki/ReflectionExplained)]**:对应 Java 反射能力的 Guava 工具类。
48 |
49 |
50 |
51 |
52 | ## Guava 的使用方法:
53 |
54 | 如果我们使用 Maven 进行项目管理,那么我们只需要在`POM.xml`中添加如下依赖:
55 |
56 | ```
57 |
58 | com.google.guava
59 | guava
60 | 28.2-jre
61 |
62 | 28.2-android
63 |
64 | ```
65 |
66 | 而如果我们使用 Gradle 进行项目管理,那么我们则需要在`config.gradle`中添加如下依赖:
67 |
68 | ```
69 | dependencies {
70 | // Pick one:
71 |
72 | // 1. Use Guava in your implementation only:
73 | implementation("com.google.guava:guava:28.2-jre")
74 |
75 | // 2. Use Guava types in your public API:
76 | api("com.google.guava:guava:28.2-jre")
77 |
78 | // 3. Android - Use Guava in your implementation only:
79 | implementation("com.google.guava:guava:28.2-android")
80 |
81 | // 4. Android - Use Guava types in your public API:
82 | api("com.google.guava:guava:28.2-android")
83 | }
84 | ```
85 |
86 | ---------
87 |
88 | English Original Editon: [Guava - User Guide](https://github.com/google/guava/wiki)
89 |
--------------------------------------------------------------------------------
/articles/basic-utilities/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/basic-utilities/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/basic-utilities/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/basic-utilities/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/basic-utilities/using-and-avoiding-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/caches/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/caches/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/caches/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/caches/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/caches/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/collections/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/collections/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/collections/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/collections/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/collections/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/concurrency/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/concurrency/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/concurrency/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/concurrency/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/concurrency/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/event-bus/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/event-bus/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/event-bus/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/event-bus/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/event-bus/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/functional-idioms/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/functional-idioms/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/functional-idioms/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/functional-idioms/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/functional-idioms/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/graphs/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/graphs/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/graphs/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/graphs/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/graphs/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/hashing/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/hashing/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/hashing/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/hashing/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/hashing/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/io/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/io/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/io/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/io/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/io/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/math/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/math/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/math/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/math/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/math/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/primitives/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/primitives/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/primitives/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/primitives/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/primitives/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/ranges/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/ranges/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/ranges/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/ranges/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/ranges/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/reflection/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/reflection/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/reflection/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/reflection/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/reflection/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------
/articles/strings/about-null.md:
--------------------------------------------------------------------------------
1 | # 使用和避免`null`
2 |
3 | > “`null`,糟糕透啦!” —— Doug Lea.
4 |
5 | > “我称`null`为百亿美金的错误!” —— C. A. R. Hoare.
6 |
7 | 轻率地使用`null`可能导致很多令人惊愕的问题。通过研究谷歌的代码,我们发现:95% 的集合不接受`null`作为元素,因此相比于默默地接受`null`,使用快速失败的操作拒绝`null`值对开发者更有帮助。
8 |
9 | 此外,`null`的模糊性会让人很不爽。我们很难知道返回值是`null`代表着什么意思,例如当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。`null`可以表示成功,也可以表示失败,几乎意味着任何事情。使用除`null`之外的某些其他值,可以让你表达的含义更清晰。
10 |
11 | 在某些场景下,使用`null`也确实是正确的。例如,在内存和速度方面,`null`就是廉价的,而且在对象数组中,出现`null`也是不可避免的。但是相对于库来说,在应用代码中,`null`往往是导致混乱、疑难问题和含义模糊的根源。就像我们上面谈到的,当`Map.get(key)`返回`null`时,既可能是 Map 中对应`key`的值是`null`,也可能是 Map 中根本就没有对应`key`的值。最关键的是,`null`根本就没有给出空值到底意味着什么。
12 |
13 | 正是由于这些原因,很多的 Guava 工具类都被设计为针对`null`是快速失败的,除非工具类本身对`null`是友好的。此外,Guava 提供了很多工具类,可以让我们在必须使用`null`时用起来更简单,也可以让我们避免使用`null`.
14 |
15 | ## 具体案例
16 |
17 | 不要在`Set`中使用`null`,也不要把`null`作为 Map 的键;在查询操作中,使用一个特殊值表示`null`,这会让我们的语言更加清晰。
18 |
19 | 如果你想使用`null`作为 Map 中某个键的值,最好不要这么做;单独的维护一个键为空或者非空的`Set`更好一些。毕竟 Map 中对应于某个键的值为空,或者根本就没有值,这是很容易混淆的情况。因此,最好的方法就是将这些键分开,并且仔细想想,在你的应用中,值为`null`的键到底有什么含义。
20 |
21 | 如果你在`List`中使用`null`,并且列表是稀疏的,那么使用`Map`可能会更高效,并且可能更符合你潜在的需求。
22 |
23 | 此外,我们可以考虑一下使用自然的`null`对象的情况。虽然这样的情况并不多,但还是有的,例如有一个枚举类型,添加了一个常量来表示`null`。还例如,在`java.math.RoundingMode`里面有一个常量`UNNECESSARY`,它表示一种不做任何舍入操作的模式,如果用这种模式做舍入操作,则会抛出异常。
24 |
25 | 如果你确实需要使用`null`值,并且使用 Guava 的集合会有一些问题,那么你可以选择其他的实现。例如,使用 JDK 中的`Collections.unmodifiableList`代替 Guava 中的`ImmutableList`.
26 |
27 | ## Optional
28 |
29 | 一般情况下,我们使用`null`表示某种缺失的情况:或许在某个值应该存在的地方,没有值,或者根本就找不到对应的值。例如,通过 Map 的键来获取值的时候,如果对应于某个键的值不存在,`Map.get`就会返回`null`.
30 |
31 | `Optional`是一个用非空的值代替引用`T`有可能为空的方法。一个`Optional`可能包括非空的`T`引用(在这种情况下,我们称之为“引用存在”),也可能什么都不包含(在这种情况下,我们称之为“引用缺失”)。但无论如何,`Optional`绝不会说它包含`null`.
32 |
33 | ```
34 | Optional possible = Optional.of(5);
35 | possible.isPresent(); // returns true
36 | possible.get(); // returns 5
37 | ```
38 |
39 | `Optional`不打算直接模拟其他编程环境中的`option` or `maybe`语义,尽管它们确实有些相似。
40 |
41 | 在这里,我们列出了一些最常见的`Optional`操作。
42 |
43 | ## 创建`Optional`实例
44 |
45 | 这里给出的都是`Optional`的静态方法。
46 |
47 | | 方法 | 描述 |
48 | | ------------- |:-------------:|
49 | | [`Optional.of(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 创建值非空的`Optional`实例,如果值为空则快速失败 |
50 | | [`Optional.absent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回某些类型引用缺失的`Optional`实例 |
51 | | [`Optional.fromNullable(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 将可能为空的引用传入`Option`实例,如果引用非空则表示存在;引用为`null`,则表示缺失 |
52 |
53 | ## 查询方法
54 |
55 | 下面都是非静态的方法,因此需要特定的`Optional`实例来调用。
56 |
57 | | 方法 | 描述 |
58 | | ------------- |:-------------:|
59 | | [`boolean isPresent()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 如果`Optional`包含非`null`的引用,则返回`true` |
60 | | [`T get()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的实例,若引用缺失,则抛出`java.lang.IllegalStateException`|
61 | | [`T or(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回指定的值 |
62 | | [`T orNull()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含的引用,若引用缺失,返回`null`. 此为`fromNullable`的逆操作。 |
63 | | [`Set asSet()`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Optional.html#of%28T%29) | 返回`Optional`所包含引用的单例不变集合,如果引用存在,返回一个只有单一元素的集合;如果引用缺失,返回一个空集合。|
64 |
65 | 除了上面给出的方法之外,`Optional`还提供了很多有用的工具方法,具体可以通过`Javadoc`来查看详细的资料。
66 |
67 | ## 使用`Optional`有什么意义?
68 |
69 | 除了增加`null`的可读性之外,`Optional`最大的优点就在于它是一种傻瓜式的防御机制。如果你想让你的程序编译通过,那么它就会强迫你去积极思考引用缺失的情况。使用`null`很容易让我们忽略某些情况,尽管`FindBugs`可以给我们提供帮助,但我们并不认为这种解决方法很好。
70 |
71 | 特别地,当你返回一个值的时候,既可以是引用存在也可以是引用缺失。你(或者其他人)更容易忘记`other.method(a, b)`可以返回一个空值,就像你在实现一个方法`other.method`的时候,你也可能忘记参数`a`可以是一个`null`值一样。而将方法的返回类型指定为`Optional`,也可以迫使调用者思考返回为引用缺失的情形。
72 |
73 | ## 便利的方法
74 |
75 | 当你想使用某些默认值代替一个`null`值的时候,可以使用`MoreObjects.firstNonNull(T, T)`方法。就像这个方法的名字提示的一样,如果输入的两个参数值都为`null`,则会抛出`NullPointerException`异常。如果你使用`Optional`的话,这里有一个更好的替换方案,例如`first.or(second)`。
76 |
77 | 在`Strings`类中,也提供了很多可以处理`String`值可能为空的方法。特别得,我们提供了恰当的名称:
78 |
79 | | 方法签名 |
80 | | ------------- |
81 | | [`emptyToNull(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
82 | | [`isNullOrEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
83 | | [`nullToEmpty(String)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Strings.html#emptyToNull(java.lang.String)) |
84 |
85 | 我们要强调的是,这些方法主要用来与一些不友好的 API 进行交互,例如`null`字符串和空字符串等等。每当你写下混淆`null`和空字符串的时候,Guava 团队的成员都泪流满面。正确的做法是将空字符串和`null`字符串区别对待,但如果把两者同等对待,这就是要出 bug 的节奏啊!
86 |
87 | ----------
88 | **原文链接**:[Google Guava - UsingAndAvoidingNullExplained](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained).
89 |
--------------------------------------------------------------------------------
/articles/strings/common-object-methods.md:
--------------------------------------------------------------------------------
1 | # 通用 Object 方法
2 |
3 | ## equals
4 |
5 | 当你的对象含有的多个字段可能为`null`的时候,实现`Object.equals`会很痛苦,因为你不得不分别对它们进行`null`检查。使用[`Objects.equal`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#equal%28java.lang.Object,%20java.lang.Object%29)能够帮助你用一个对`null`敏感的方式执行`equals`检查,而不必冒着抛出`NullPointerException`的风险。例如:
6 |
7 | ```
8 | Objects.equal("a", "a"); // returns true
9 | Objects.equal(null, "a"); // returns false
10 | Objects.equal("a", null); // returns false
11 | Objects.equal(null, null); // returns true
12 | ```
13 |
14 | *注意*:在 JDK 7 中提供了等效的[`Objects.equals`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals%28java.lang.Object,%20java.lang.Object%29)方法。
15 |
16 | ## hashCode
17 |
18 | 散列一个对象的所有字段应该更简单。Guava 的[`Objects.hashCode(Object...)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Objects.html#hashCode%28java.lang.Object...%29)会对指定的字段构建出一个合理的、顺序敏感的散列值。我们应该使用`Objects.hashCode(field1, field2, ..., fieldn)`来代替手工的构建散列值。
19 |
20 | *注意*:在 JDK 7 中提供了等效的[`Objects.hash(Object...)`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...))方法。
21 |
22 | ## toString
23 |
24 | 一个好的`toString`方法在调试时是无价之宝,不过编写`toString`方法却有些痛苦。使用[`MoreObjects.toStringHelper`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/MoreObjects.html#toStringHelper%28java.lang.Object%29)可以让你非常轻松的创建一个有用的`toString`方法。例如:
25 |
26 | ```
27 | // Returns "ClassName{x=1}"
28 | MoreObjects.toStringHelper(this)
29 | .add("x", 1)
30 | .toString();
31 |
32 | // Returns "MyObject{x=1}"
33 | MoreObjects.toStringHelper("MyObject")
34 | .add("x", 1)
35 | .toString();
36 | ```
37 |
38 | ## compare/compareTo
39 |
40 | 直接实现`Comparator`或者`Comparable`接口也让人头痛。考虑下面这种情况:
41 |
42 | ```
43 | class Person implements Comparable {
44 | private String lastName;
45 | private String firstName;
46 | private int zipCode;
47 |
48 | public int compareTo(Person other) {
49 | int cmp = lastName.compareTo(other.lastName);
50 | if (cmp != 0) {
51 | return cmp;
52 | }
53 | cmp = firstName.compareTo(other.firstName);
54 | if (cmp != 0) {
55 | return cmp;
56 | }
57 | return Integer.compare(zipCode, other.zipCode);
58 | }
59 | }
60 | ```
61 | 这段代码冗长、混乱,而且不便调试。我们应该能够做的更好。为此,Guava 提供了[`ComparisonChain`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/ComparisonChain.html)。`ComparisonChain`执行一种“懒惰”的比较策略:它执行比较操作直至发现非零的结果,在那之后的输入都将被忽略。例如:
62 |
63 | ```
64 | public int compareTo(Foo that) {
65 | return ComparisonChain.start()
66 | .compare(this.aString, that.aString)
67 | .compare(this.anInt, that.anInt)
68 | .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
69 | .result();
70 | }
71 | ```
72 | 这种流畅的风格更具可读性,发生错误的几率更小,并且足够聪明以避免不必要的工作。在 Guava 的“流畅比较器”类`Ordering`中,我们能够看到更多的比较器工具。
73 |
74 | -------
75 |
76 |
77 | **原文链接**:[Google Guava - CommonObjectUtilitiesExplained](https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained).
78 |
--------------------------------------------------------------------------------
/articles/strings/preconditions.md:
--------------------------------------------------------------------------------
1 | # 前置条件
2 |
3 | Guava 提供了很多用于进行前置条件检查的工具,我们强烈建议静态导入这些方法。
4 |
5 | 每个方法都用三种形式:
6 |
7 | - 没有额外的参数。抛出的任何异常都没有错误信息。
8 | - 有一个额外的`Object`参数。抛出的任何异常都带有一个`object.toString()`的错误信息。
9 | - 有一个额外的`String`参数以及任意数量的附加`Object`参数。这些行为类似于`printf`,但是为了 GWT 兼容性和高效性仅允许`%s`,例如:
10 |
11 | ```
12 | checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
13 | checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
14 | ```
15 |
16 | | 签名(不包括额外参数) | 描述 | 失败时抛出的异常 |
17 | | ------------- |:-------------:| -----:|
18 | | [`checkArgument(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查`boolean`型是否为`true`,用于校验传递给方法的参数 | `IllegalArgumentException` |
19 | | [`checkNotNull(T)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查值是否为`null`,直接返回参数值,所以你可以在代码中直接使用`checkNotNull(value)` | `NullPointerException` |
20 | | [`checkState(boolean)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 检查对象的某些状态,而不依赖于方法参数。例如,一个`Iterator `可能使用这个方法来检查在调用任何`remove`之前调用`next` | `IllegalStateException` |
21 | | [`checkElementIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串和数组中检查`index`是否有效。一个有效的`index`应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或者数组,只需传递指定的长度即可。此方法返回`index`| `IndexOutOfBoundsException` |
22 | | [`checkPositionIndex(int index, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29)| 检查`index`是否为指定大小的列表、字符串或数组的有效位置索引。一个有效的位置索引应该是在`0`与指定长度之间的值。你不需要直接传递列表、字符串或数组,只需传递它的大小即可。此方法返回`index` | `IndexOutOfBoundsException` |
23 | | [`checkPositionIndexes(int start, int end, int size)`](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Preconditions.html#checkState%28boolean%29) | 在指定长度的列表、字符串或数组中检查`[start, end)`的范围是否有效。此方法自带错误消息 | `IndexOutOfBoundsException` |
24 |
25 | 相比 Apache Commons 提供的类似方法,我们把 Guava 中的前置条件作为首选方法是有原因的,简要地:
26 |
27 | - 在静态导入后,Guava 的方法清晰明了。`checkNotNull`清楚地描述它能做了什么以及会抛出什么异常;
28 | - `checkNotNull`在校验之后直接返回参数,允许你在构造函数中保持字段的单行赋值风格,例如:`this.field = checkNotNull(field)`
29 | - 简单的、参数可变的`printf`风格异常信息。(正是基于这个优点,让我们为什么在 JDK 7 已经引入`Objects.requireNonNull`的情况下,仍然建议你使用`checkNotNull`.)
30 |
31 | 我们建议你将前置条件放在不同的行,这可以帮助你在调试期间找出到底是哪些前置件导致的失败。另外,你应该提供有用的错误消息,这让在每个前置条件都位于不同行时更容易定位错误。
32 |
33 |
34 |
35 |
36 | -------
37 |
38 |
39 | **原文链接**:[Google Guava - PreconditionsExplained](https://github.com/google/guava/wiki/PreconditionsExplained).
40 |
--------------------------------------------------------------------------------
/articles/strings/throwable.md:
--------------------------------------------------------------------------------
1 | # 异常传播
2 |
3 | 有时候,当你捕获一个异常时,你可能想将它抛到下一个`try/catch`块。这样情况很常见,例如在出现`RuntimeException`和`Error`的情况下,不需要`try/catch`块,你也不想捕获它们,但是它们仍然被`try/catch`块捕获。
4 |
5 | Guava 提供了一些工具类来简化异常传播。例如:
6 |
7 | ```
8 | try {
9 | someMethodThatCouldThrowAnything();
10 | } catch (IKnowWhatToDoWithThisException e) {
11 | handle(e);
12 | } catch (Throwable t) {
13 | Throwables.propagateIfInstanceOf(t, IOException.class);
14 | Throwables.propagateIfInstanceOf(t, SQLException.class);
15 | throw Throwables.propagate(t);
16 | }
17 | ```
18 | 每一个方法都抛了异常,而抛出的结果,例如`Throwables.propagate(t)`,可以证明编辑器抛出了一个很有用的异常。
19 |
20 | 下面是 Guava 提供的异常传播方法的摘要:
21 |
22 | | 方法签名 | 解释 |
23 | | ------------- |-------------|
24 | | [RuntimeException propagate(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagate%28java.lang.Throwable%29) | 通过`RuntimeException`或者`Error`进行异常传播,或者将异常包装进`RuntimeException`,可以保证异常的传播性。由于其返回类型是一个`RuntimeException`,所以你可以通过`throw Throwables.propagate(t)`抛出异常,而且 Java 可以识别这样的语句,并保证抛出一个异常。|
25 | | [void propagateIfInstanceOf(Throwable, Class) throws X](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当且仅当异常实例为`X`的时候,进行异常传播。 |
26 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) |当出现`RuntimeException`或者`Error`时,抛出`throwable` |
27 | | [void propagateIfPossible(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#propagateIfPossible%28java.lang.Throwable%29) | 当出现`RuntimeException`、`Error`或者`X`时,抛出`throwable` |
28 |
29 |
30 | ## `Throwables.propagate`的使用
31 |
32 | 详见「[为什么我们不赞成使用 Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)」
33 |
34 | ## 异常原因链
35 |
36 | Guava 提供了三个有用的方法,使得异常链的研究更加简单,通过这三个方法的签名就可以窥知一二:
37 |
38 | |方法签名 |
39 | | ------------- |
40 | |[Throwable getRootCause(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
41 | | [List<Throwable> getCausalChain(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
42 | | [String getStackTraceAsString(Throwable)](http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Throwables.html#getRootCause(java.lang.Throwable)) |
43 |
44 |
45 | ----------
46 |
47 |
48 | **原文链接**:[Google Guava - ThrowablesExplained](https://github.com/google/guava/wiki/ThrowablesExplained).
49 |
--------------------------------------------------------------------------------
/articles/strings/user-guide.md:
--------------------------------------------------------------------------------
1 | # Guava 中文指南
2 |
3 | Guava 项目包含若干被 Google 的 Java 项目依赖的核心类库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O 等等。Google 的开发者们每天都在使用这些工具进行项目的开发。但是查阅 Javadoc 并不总是最有效的学习这些类库的方式。在这里,我们尝试为 Guava 中一些最受欢迎和最有用的功能提供更具可读性的说明。
4 |
5 | - **基础工具[Basic utilities]**:让我们更愉快的使用 Java 语言。
6 | - 使用时避免`null`:`null`的定义很模糊,可能导致令人疑惑的错误,有时会让我们很不爽。很多的 Guava 工具类对`null`都是快速失败的,拒绝使用`null`,,而不是盲目的接收它们。
7 | - 前置条件:让你的方法更容易进行前置条件的检查。
8 | - 通用`Object`方法:简化`Object`方法的实现,例如`hashCode()`和`toString()`.
9 | - 排序:Guava 有强大且流畅的`Comparator`类。
10 | - 可抛的:简化异常和错误的检查机制。
11 | - **集合[Collections]**:Guava 扩展了 JDK 的集合体系,这是 Guava 最成熟且最受欢迎的部分。
12 | - 不可变集合:为了进行防御性编程、使用常量集合和提高效率。
13 | - 新集合类型:提供了多集合、多 Map、多表、双向 Map 等。
14 | - 强大的集合工具类:普通的操作并没有在`java.util.Collections`中提供。
15 | - 扩展工具类:装饰`Collection`?实现`Iterator`?我们让类似的操作变的更简单。
16 |
17 | - **图[Graphs]**:这是一个图结构数据的模型类库,它展现了实体以及图和实体之间的关系,主要的特点包括:
18 | - 图[Graph]:图的边缘是没有自己标识和信息的匿名实体。
19 | - 值图[ValueGraph]:图的边缘关联着非唯一的值。
20 | - 网络[Network]:图的边缘是唯一的对象。
21 | - 支持可变的、不可变的、定向的和无向的图以及其他一些属性。
22 |
23 | - **缓存[Caches]**:支持本地缓存,也支持多种缓存过期行为。
24 |
25 | - **函数风格[Functional idioms]**:Guava 的函数风格能够显著的简化代码,但请谨慎使用。
26 |
27 | - **并发[Concurrency]**:强大而简单的抽象,让编写正确的并发代码更简单。
28 | - ListenableFuture: Future,结束时触发回调 。
29 | - Service:开启和关闭服务,帮助我们处理困难的状态逻辑。
30 |
31 | - **字符串[Strings]**:非常有用的字符串处理工具,包括分割、拼接等等。
32 |
33 | - **原生类型[Primitives]**:扩展了 JDK 没有提供的原生类型(像`int`和`char`)操作,包含了某些类型的无符号变量。
34 |
35 | - **区间[Ranges]**:Guava 强大的 API 提供了基于`Comparable`类型区间比较功能,包连续类型和离散类型。
36 |
37 | - **输入输出流[I/O]**:针对 Java 5 和 Java 6 版本,简化了 I/O 操作,尤其是 I/O 流和文件操作。
38 |
39 | - **散列[Hashing]**:提供了比`Object.hashCode()`更负责的哈希实现,包含了 Bloom 过滤器。
40 |
41 | - **事件总线[EventBus]**:在不需要组件之间显示注册的情况下,提供了组件之间的发布-订阅模式的通信。
42 |
43 | - **数学运算[Math]**:优化了 JDK 已经提供的数学工具类,并彻底的测试了 JDK 没有提供的数学工具类。
44 |
45 | - **反射[Reflection]**:对应 Java 反射能力的 Guava 工具类。
46 |
47 |
48 |
49 |
50 | ----------
51 |
52 | **翻译声明**:本文翻译自 GitHub,[Google Guava - Home - User Guide](https://github.com/google/guava/wiki)。
53 |
--------------------------------------------------------------------------------