├── 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 | ![author](https://img.shields.io/badge/author-chariesgavin-blueviolet.svg)![last commit](https://img.shields.io/github/last-commit/guobinhit/guava-guide.svg)![issues](https://img.shields.io/github/issues/guobinhit/guava-guide.svg)![stars](https://img.shields.io/github/stars/guobinhit/guava-guide.svg)![forks](https://img.shields.io/github/forks/guobinhit/guava-guide.svg)![license](https://img.shields.io/github/license/guobinhit/guava-guide.svg) 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 | --------------------------------------------------------------------------------