## Chapter 5. Generics(泛型)
### Item 33: Consider typesafe heterogeneous containers(考虑类型安全的异构容器)
Common uses of generics include collections, such as `Set<E>` and `Map<K,V>`, and single-element containers, such as `ThreadLocal<T>` and `AtomicReference<T>`. In all of these uses, it is the container that is parameterized. This limits you to a fixed number of type parameters per container. Normally that is exactly what you want. A Set has a single type parameter, representing its element type; a Map has two, representing its key and value types; and so forth.
集合是泛型的常见应用之一,如 `Set<E>` 和 `Map<K,V>`,以及单元素容器,如 `ThreadLocal<T>` 和 `AtomicReference<T>`。在所有这些应用中,都是参数化的容器。这将每个容器的类型参数限制为固定数量。通常这正是你想要的。Set 只有一个类型参数,表示其元素类型;Map 有两个,表示`键`和`值`的类型;如此等等。
Sometimes, however, you need more flexibility. For example, a database row can have arbitrarily many columns, and it would be nice to be able to access all of them in a typesafe manner. Luckily, there is an easy way to achieve this effect. The idea is to parameterize the key instead of the container. Then present the parameterized key to the container to insert or retrieve a value. The generic type system is used to guarantee that the type of the value agrees with its key.
然而,有时你需要更大的灵活性。例如,一个数据库行可以有任意多列,能够以类型安全的方式访问所有这些列是很好的。幸运的是,有一种简单的方法可以达到这种效果。其思想是参数化`键`而不是容器。然后向容器提供参数化`键`以插入或检索`值`。泛型类型系统用于确保`值`的类型与`键`一致。
As a simple example of this approach, consider a Favorites class that allows its clients to store and retrieve a favorite instance of arbitrarily many types. The Class object for the type will play the part of the parameterized key. The reason this works is that class Class is generic. The type of a class literal is not simply Class, but `Class<T>`. For example, String.class is of type `Class<String>`, and Integer.class is of type `Class<Integer>`. When a class literal is passed among methods to communicate both compiletime and runtime type information, it is called a type token [Bracha04].
作为这种方法的一个简单示例,考虑一个 Favorites 类,它允许客户端存储和检索任意多种类型的 Favorites 实例。Class 类的对象将扮演参数化`键`的角色。这样做的原因是 Class 类是泛型的。Class 对象的类型不仅仅是 Class,而是 `Class<T>`。例如,String.class 的类型为 `Class<String>`、Integer.class 的类型为 `Class<Integer>`。在传递编译时和运行时类型信息的方法之间传递类 Class 对象时,它被称为类型标记[Bracha04]。
The API for the Favorites class is simple. It looks just like a simple map, except that the key is parameterized instead of the map. The client presents a Class object when setting and getting favorites. Here is the API:
Favorites 类的 API 很简单。它看起来就像一个简单的 Map,只不过`键`是参数化的,而不是整个 Map。客户端在设置和获取 Favorites 实例时显示一个 Class 对象。以下是 API:
```
// Typesafe heterogeneous container pattern - API
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
```
Here is a sample program that exercises the Favorites class, storing, retrieving, and printing a favorite String, Integer, and Class instance:
下面是一个示例程序,它演示了 Favorites 类、存储、检索和打印 Favorites 字符串、整数和 Class 实例:
```
// Typesafe heterogeneous container pattern - client
public static void main(String[] args) {
Favorites f = new Favorites();
f.putFavorite(String.class, "Java");
f.putFavorite(Integer.class, 0xcafebabe);
f.putFavorite(Class.class, Favorites.class);
String favoriteString = f.getFavorite(String.class);
int favoriteInteger = f.getFavorite(Integer.class);
Class<?> favoriteClass = f.getFavorite(Class.class);
System.out.printf("%s %x %s%n", favoriteString,favoriteInteger, favoriteClass.getName());
}
```
As you would expect, this program prints Java cafebabe Favorites. Note, incidentally, that Java’s printf method differs from C’s in that you should use %n where you’d use \n in C. The %n generates the applicable platform-specific line separator, which is \n on many but not all platforms.
如你所料,这个程序打印 Java cafebabe Favorites。顺便提醒一下,Java 的 printf 方法与 C 的不同之处在于,你应该在 C 中使用 \n 的地方改用 %n。
**译注:`favoriteClass.getName()` 的打印结果与 Favorites 类所在包名有关,结果应为:包名.Favorites**
A Favorites instance is typesafe: it will never return an Integer when you ask it for a String. It is also heterogeneous: unlike an ordinary map, all the keys are of different types. Therefore, we call Favorites a typesafe heterogeneous container.
Favorites 的实例是类型安全的:当你向它请求一个 String 类型时,它永远不会返回一个 Integer 类型。它也是异构的:与普通 Map 不同,所有`键`都是不同类型的。因此,我们将 Favorites 称为一个类型安全异构容器。
The implementation of Favorites is surprisingly tiny. Here it is, in its entirety:
Favorites 的实现非常简短。下面是全部内容:
```
// Typesafe heterogeneous container pattern - implementation
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<>();
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(Objects.requireNonNull(type), instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
```
There are a few subtle things going on here. Each Favorites instance is backed by a private `Map<Class<?>, Object>` called favorites. You might think that you couldn’t put anything into this Map because of the unbounded wildcard type, but the truth is quite the opposite. The thing to notice is that the wildcard type is nested: it’s not the type of the map that’s a wildcard type but the type of its key. This means that every key can have a different parameterized type: one can be `Class<String>`, the next `Class<Integer>`, and so on. That’s where the heterogeneity comes from.
这里发生了一些微妙的事情。每个 Favorites 实例都由一个名为 favorites 的私有 `Map<Class<?>, Object>` 支持。你可能认为由于通配符类型是无界的,所以无法将任何内容放入此映射中,但事实恰恰相反。需要注意的是,通配符类型是嵌套的:通配符类型不是 Map 的类型,而是`键`的类型。这意味着每个`键`都可以有不同的参数化类型:一个可以是 `Class<String>`,下一个是 `Class<Integer>`,等等。这就是异构的原理。
The next thing to notice is that the value type of the favorites Map is simply Object. In other words, the Map does not guarantee the type relationship between keys and values, which is that every value is of the type represented by its key. In fact, Java’s type system is not powerful enough to express this. But we know that it’s true, and we take advantage of it when the time comes to retrieve a favorite.
接下来要注意的是 favorites 的`值`类型仅仅是 Object。换句话说,Map 不保证`键`和`值`之间的类型关系,即每个`值`都是其`键`所表示的类型。实际上,Java 的类型系统还没有强大到足以表达这一点。但是我们知道这是事实,当需要检索一个 favorite 时,我们会利用它。
The putFavorite implementation is trivial: it simply puts into favorites a mapping from the given Class object to the given favorite instance. As noted, this discards the “type linkage” between the key and the value; it loses the knowledge that the value is an instance of the key. But that’s OK, because the getFavorites method can and does reestablish this linkage.
putFavorite 的实现很简单:它只是将从给定 Class 对象到给定 Favorites 实例的放入 favorites 中。如前所述,这将丢弃`键`和`值`之间的「类型关联」;将无法确定`值`是`键`的实例。但这没关系,因为 getFavorites 方法可以重新建立这个关联。
The implementation of getFavorite is trickier than that of putFavorite. First, it gets from the favorites map the value corresponding to the given Class object. This is the correct object reference to return, but it has the wrong compile-time type: it is Object (the value type of the favorites map) and we need to return a T. So, the getFavorite implementation dynamically casts the object reference to the type represented by the Class object, using Class’s cast method.
getFavorite 的实现比 putFavorite 的实现更复杂。首先,它从 favorites 中获取与给定 Class 对象对应的`值`。这是正确的对象引用返回,但它有错误的编译时类型:它是 Object(favorites 的`值`类型),我们需要返回一个 T。因此,getFavorite 的实现通过使用 Class 的 cast 方法,将对象引用类型动态转化为所代表的 Class 对象。
The cast method is the dynamic analogue of Java’s cast operator. It simply checks that its argument is an instance of the type represented by the Class object. If so, it returns the argument; otherwise it throws a ClassCastException. We know that the cast invocation in getFavorite won’t throw ClassCastException, assuming the client code compiled cleanly. That is to say, we know that the values in the favorites map always match the types of their keys.
cast 方法是 Java 的 cast 运算符的动态模拟。它只是检查它的参数是否是类对象表示的类型的实例。如果是,则返回参数;否则它将抛出 ClassCastException。我们知道 getFavorite 中的强制转换调用不会抛出 ClassCastException,假设客户端代码已正确地编译。也就是说,我们知道 favorites 中的`值`总是与其`键`的类型匹配。
So what does the cast method do for us, given that it simply returns its argument? The signature of the cast method takes full advantage of the fact that class Class is generic. Its return type is the type parameter of the Class object:
如果 cast 方法只是返回它的参数,那么它会为我们做什么呢?cast 方法的签名充分利用了 Class 类是泛型的这一事实。其返回类型为 Class 对象的类型参数:
```
public class Class<T> {
T cast(Object obj);
}
```
This is precisely what’s needed by the getFavorite method. It is what allows us to make Favorites typesafe without resorting to an unchecked cast to T.
这正是 getFavorite 方法所需要的。它使我们能够使 Favorites 类型安全,而不需要对 T 进行 unchecked 的转换。
There are two limitations to the Favorites class that are worth noting. First, a malicious client could easily corrupt the type safety of a Favorites instance, by using a Class object in its raw form. But the resulting client code would generate an unchecked warning when it was compiled. This is no different from a normal collection implementations such as HashSet and HashMap. You can easily put a String into a `HashSet<Integer>` by using the raw type HashSet (Item 26). That said, you can have runtime type safety if you’re willing to pay for it. The way to ensure that Favorites never violates its type invariant is to have the putFavorite method check that instance is actually an instance of the type represented by type, and we already know how to do this. Just use a dynamic cast:
Favorites 类有两个`值`得注意的限制。首先,恶意客户端很容易通过使用原始形式的类对象破坏 Favorites 实例的类型安全。但是生成的客户端代码在编译时将生成一个 unchecked 警告。这与普通的集合实现(如 HashSet 和 HashMap)没有什么不同。通过使用原始类型 HashSet([Item-26](/Chapter-5/Chapter-5-Item-26-Do-not-use-raw-types.md)),可以轻松地将 String 类型放入 `HashSet<Integer>` 中。也就是说,如果你愿意付出代价的话,你可以拥有运行时类型安全。确保 Favorites 不会违反其类型不变量的方法是让 putFavorite 方法检查实例是否是 type 表示的类型的实例,我们已经知道如何做到这一点。只需使用动态转换:
```
// Achieving runtime type safety with a dynamic cast
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(type, type.cast(instance));
}
```
There are collection wrappers in java.util.Collections that play the same trick. They are called checkedSet, checkedList, checkedMap, and so forth. Their static factories take a Class object (or two) in addition to a collection (or map). The static factories are generic methods, ensuring that the compile-time types of the Class object and the collection match. The wrappers add reification to the collections they wrap. For example, the wrapper throws a ClassCastException at runtime if someone tries to put a Coin into your `Collection<Stamp>`. These wrappers are useful for tracking down client code that adds an incorrectly typed element to a collection, in an application that mixes generic and raw types.
java.util.Collections 中的集合包装器也具有相同的功能。它们被称为 checkedSet、checkedList、checkedMap,等等。除了集合(或 Map)外,它们的静态工厂还接受一个(或两个)Class 对象。静态工厂是通用方法,确保 Class 对象和集合的编译时类型匹配。包装器将具体化添加到它们包装的集合中。例如,如果有人试图将 Coin 放入 `Collection<Stamp>` 中,包装器将在运行时抛出 ClassCastException。在混合了泛型类型和原始类型的应用程序中,这些包装器对跟踪将类型错误的元素添加到集合中的客户端代码非常有用。
The second limitation of the Favorites class is that it cannot be used on a non-reifiable type (Item 28). In other words, you can store your favorite String or String[], but not your favorite `List<String>`. If you try to store your favorite `List<String>`, your program won’t compile. The reason is that you can’t get a Class object for `List<String>`. The class literal `List<String>.class` is a syntax error, and it’s a good thing, too. `List<String>` and `List<Integer>` share a single Class object, which is List.class. It would wreak havoc with the internals of a Favorites object if the “type literals” `List<String>.class` and `List<Integer>.class` were legal and returned the same object reference. There is no entirely satisfactory workaround for this limitation.
Favorites 类的第二个限制是它不能用于不可具体化的类型([Item-28](/Chapter-5/Chapter-5-Item-28-Prefer-lists-to-arrays.md))。换句话说,你可以存储的 Favorites 实例类型为 String 类型或 String[],但不能存储 `List<String>`。原因是你不能为 `List<String>` 获取 Class 对象,`List<String>.class` 是一个语法错误,这也是一件好事。`List<String>` 和 `List<Integer>` 共享一个 Class 对象,即 List.class。如果「字面类型」`List<String>.class` 和 `List<Integer>.class` 是合法的,并且返回相同的对象引用,那么它将严重破坏 Favorites 对象的内部结构。对于这个限制,没有完全令人满意的解决方案。
The type tokens used by Favorites are unbounded: getFavorite and put-Favorite accept any Class object. Sometimes you may need to limit the types that can be passed to a method. This can be achieved with a bounded type token, which is simply a type token that places a bound on what type can be represented, using a bounded type parameter (Item 30) or a bounded wildcard (Item 31).
Favorites 使用的类型标记是无界的:getFavorite 和 put-Favorite 接受任何 Class 对象。有时你可能需要限制可以传递给方法的类型。这可以通过有界类型标记来实现,它只是一个类型标记,使用有界类型参数([Item-30](/Chapter-5/Chapter-5-Item-30-Favor-generic-methods.md))或有界通配符([Item-31](/Chapter-5/Chapter-5-Item-31-Use-bounded-wildcards-to-increase-API-flexibility.md))对可以表示的类型进行绑定。
The annotations API (Item 39) makes extensive use of bounded type tokens. For example, here is the method to read an annotation at runtime. This method comes from the AnnotatedElement interface, which is implemented by the reflective types that represent classes, methods, fields, and other program elements:
annotation API([Item-39](/Chapter-6/Chapter-6-Item-39-Prefer-annotations-to-naming-patterns.md))广泛使用了有界类型标记。例如,下面是在运行时读取注释的方法。这个方法来自 AnnotatedElement 接口,它是由表示类、方法、字段和其他程序元素的反射类型实现的:
```
public <T extends Annotation>
T getAnnotation(Class<T> annotationType);
```
The argument, annotationType, is a bounded type token representing an annotation type. The method returns the element’s annotation of that type, if it has one, or null, if it doesn’t. In essence, an annotated element is a typesafe heterogeneous container whose keys are annotation types.
参数 annotationType 是表示注释类型的有界类型标记。该方法返回该类型的元素注释(如果有的话),或者返回 null(如果没有的话)。本质上,带注释的元素是一个类型安全的异构容器,其`键`是注释类型。
Suppose you have an object of type `Class<?>` and you want to pass it to a method that requires a bounded type token, such as getAnnotation. You could cast the object to `Class<? extends Annotation>`, but this cast is unchecked, so it would generate a compile-time warning (Item 27). Luckily, class Class provides an instance method that performs this sort of cast safely (and dynamically). The method is called asSubclass, and it casts the Class object on which it is called to represent a subclass of the class represented by its argument. If the cast succeeds, the method returns its argument; if it fails, it throws a ClassCastException.
假设你有一个 `Class<?>` 类型的对象,并且希望将其传递给一个需要有界类型令牌(例如 getAnnotation)的方法。你可以将对象强制转换为 `Class<? extends Annotation>`,但是这个强制转换是未选中的,因此它将生成一个编译时警告([Item-27](/Chapter-5/Chapter-5-Item-27-Eliminate-unchecked-warnings.md))。幸运的是,class 类提供了一个实例方法,可以安全地(动态地)执行这种类型的强制转换。该方法称为 asSubclass,它将类对象强制转换为它所调用的类对象,以表示由其参数表示的类的子类。如果转换成功,则该方法返回其参数;如果失败,则抛出 ClassCastException。
Here’s how you use the asSubclass method to read an annotation whose type is unknown at compile time. This method compiles without error or warning:
下面是如何使用 asSubclass 方法读取在编译时类型未知的注释。这个方法编译没有错误或警告:
```
// Use of asSubclass to safely cast to a bounded type token
static Annotation getAnnotation(AnnotatedElement element,String annotationTypeName) {
Class<?> annotationType = null; // Unbounded type token
try {
annotationType = Class.forName(annotationTypeName);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}
```
In summary, the normal use of generics, exemplified by the collections APIs, restricts you to a fixed number of type parameters per container. You can get around this restriction by placing the type parameter on the key rather than the container. You can use Class objects as keys for such typesafe heterogeneous containers. A Class object used in this fashion is called a type token. You can also use a custom key type. For example, you could have a DatabaseRow type representing a database row (the container), and a generic type `Column<T>` as its key.
总之,以集合的 API 为例的泛型在正常使用时将每个容器的类型参数限制为固定数量。你可以通过将类型参数放置在`键`上而不是容器上来绕过这个限制。你可以使用 Class 对象作为此类类型安全异构容器的`键`。以这种方式使用的 Class 对象称为类型标记。还可以使用自定义`键`类型。例如,可以使用 DatabaseRow 类型表示数据库行(容器),并使用泛型类型 `Column<T>` 作为它的`键`。
---
**[Back to contents of the chapter(返回章节目录)](/Chapter-5/Chapter-5-Introduction.md)**
- **Previous Item(上一条目):[Item 32: Combine generics and varargs judiciously(明智地合用泛型和可变参数)](/Chapter-5/Chapter-5-Item-32-Combine-generics-and-varargs-judiciously.md)**
- **Next Item(下一条目):[Chapter 6 Introduction(章节介绍)](/Chapter-6/Chapter-6-Introduction.md)**
- Chapter 2. Creating and Destroying Objects(创建和销毁对象)
- Item 1: Consider static factory methods instead of constructors(考虑以静态工厂方法代替构造函数)
- Item 2: Consider a builder when faced with many constructor parameters(在面对多个构造函数参数时,请考虑构建器)
- Item 3: Enforce the singleton property with a private constructor or an enum type(使用私有构造函数或枚举类型实施单例属性)
- Item 4: Enforce noninstantiability with a private constructor(用私有构造函数实施不可实例化)
- Item 5: Prefer dependency injection to hardwiring resources(依赖注入优于硬连接资源)
- Item 6: Avoid creating unnecessary objects(避免创建不必要的对象)
- Item 7: Eliminate obsolete object references(排除过时的对象引用)
- Item 8: Avoid finalizers and cleaners(避免使用终结器和清除器)
- Item 9: Prefer try with resources to try finally(使用 try-with-resources 优于 try-finally)
- Chapter 3. Methods Common to All Objects(对象的通用方法)
- Item 10: Obey the general contract when overriding equals(覆盖 equals 方法时应遵守的约定)
- Item 11: Always override hashCode when you override equals(当覆盖 equals 方法时,总要覆盖 hashCode 方法)
- Item 12: Always override toString(始终覆盖 toString 方法)
- Item 13: Override clone judiciously(明智地覆盖 clone 方法)
- Item 14: Consider implementing Comparable(考虑实现 Comparable 接口)
- Chapter 4. Classes and Interfaces(类和接口)
- Item 15: Minimize the accessibility of classes and members(尽量减少类和成员的可访问性)
- Item 16: In public classes use accessor methods not public fields(在公共类中,使用访问器方法,而不是公共字段)
- Item 17: Minimize mutability(减少可变性)
- Item 18: Favor composition over inheritance(优先选择复合而不是继承)
- Item 19: Design and document for inheritance or else prohibit it(继承要设计良好并且具有文档,否则禁止使用)
- Item 20: Prefer interfaces to abstract classes(接口优于抽象类)
- Item 21: Design interfaces for posterity(为后代设计接口)
- Item 22: Use interfaces only to define types(接口只用于定义类型)
- Item 23: Prefer class hierarchies to tagged classes(类层次结构优于带标签的类)
- Item 24: Favor static member classes over nonstatic(静态成员类优于非静态成员类)
- Item 25: Limit source files to a single top level class(源文件仅限有单个顶层类)
- Chapter 5. Generics(泛型)
- Item 26: Do not use raw types(不要使用原始类型)
- Item 27: Eliminate unchecked warnings(消除 unchecked 警告)
- Item 28: Prefer lists to arrays(list 优于数组)
- Item 29: Favor generic types(优先使用泛型)
- Item 30: Favor generic methods(优先使用泛型方法)
- Item 31: Use bounded wildcards to increase API flexibility(使用有界通配符增加 API 的灵活性)
- Item 32: Combine generics and varargs judiciously(明智地合用泛型和可变参数)
- Item 33: Consider typesafe heterogeneous containers(考虑类型安全的异构容器)
- Chapter 6. Enums and Annotations(枚举和注解)
- Item 34: Use enums instead of int constants(用枚举类型代替 int 常量)
- Item 35: Use instance fields instead of ordinals(使用实例字段替代序数)
- Item 36: Use EnumSet instead of bit fields(用 EnumSet 替代位字段)
- Item 37: Use EnumMap instead of ordinal indexing(使用 EnumMap 替换序数索引)
- Item 38: Emulate extensible enums with interfaces(使用接口模拟可扩展枚举)
- Item 39: Prefer annotations to naming patterns(注解优于命名模式)
- Item 40: Consistently use the Override annotation(坚持使用 @Override 注解)
- Item 41: Use marker interfaces to define types(使用标记接口定义类型)
- Chapter 7. Lambdas and Streams(λ 表达式和流)
- Item 42: Prefer lambdas to anonymous classes(λ 表达式优于匿名类)
- Item 43: Prefer method references to lambdas(方法引用优于 λ 表达式)
- Item 44: Favor the use of standard functional interfaces(优先使用标准函数式接口)
- Item 45: Use streams judiciously(明智地使用流)
- Item 46: Prefer side effect free functions in streams(在流中使用无副作用的函数)
- Item 47: Prefer Collection to Stream as a return type(优先选择 Collection 而不是流作为返回类型)
- Item 48: Use caution when making streams parallel(谨慎使用并行流)
- Chapter 8. Methods(方法)
- Item 49: Check parameters for validity(检查参数的有效性)
- Item 50: Make defensive copies when needed(在需要时制作防御性副本)
- Item 51: Design method signatures carefully(仔细设计方法签名)
- Item 52: Use overloading judiciously(明智地使用重载)
- Item 53: Use varargs judiciously(明智地使用可变参数)
- Item 54: Return empty collections or arrays, not nulls(返回空集合或数组,而不是 null)
- Item 55: Return optionals judiciously(明智地的返回 Optional)
- Item 56: Write doc comments for all exposed API elements(为所有公开的 API 元素编写文档注释)
- Chapter 9. General Programming(通用程序设计)
- Item 57: Minimize the scope of local variables(将局部变量的作用域最小化)
- Item 58: Prefer for-each loops to traditional for loops(for-each 循环优于传统的 for 循环)
- Item 59: Know and use the libraries(了解并使用库)
- Item 60: Avoid float and double if exact answers are required(若需要精确答案就应避免使用 float 和 double 类型)
- Item 61: Prefer primitive types to boxed primitives(基本数据类型优于包装类)
- Item 62: Avoid strings where other types are more appropriate(其他类型更合适时应避免使用字符串)
- Item 63: Beware the performance of string concatenation(当心字符串连接引起的性能问题)
- Item 64: Refer to objects by their interfaces(通过接口引用对象)
- Item 65: Prefer interfaces to reflection(接口优于反射)
- Item 66: Use native methods judiciously(明智地使用本地方法)
- Item 67: Optimize judiciously(明智地进行优化)
- Item 68: Adhere to generally accepted naming conventions(遵守被广泛认可的命名约定)
- Chapter 10. Exceptions(异常)
- Item 69: Use exceptions only for exceptional conditions(仅在确有异常条件下使用异常)
- Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors(对可恢复情况使用 checked 异常,对编程错误使用运行时异常)
- Item 71: Avoid unnecessary use of checked exceptions(避免不必要地使用 checked 异常)
- Item 72: Favor the use of standard exceptions(鼓励复用标准异常)
- Item 73: Throw exceptions appropriate to the abstraction(抛出能用抽象解释的异常)
- Item 74: Document all exceptions thrown by each method(为每个方法记录会抛出的所有异常)
- Item 75: Include failure capture information in detail messages(异常详细消息中应包含捕获失败的信息)
- Item 76: Strive for failure atomicity(尽力保证故障原子性)
- Item 77: Don’t ignore exceptions(不要忽略异常)
- Chapter 11. Concurrency(并发)
- Item 78: Synchronize access to shared mutable data(对共享可变数据的同步访问)
- Item 79: Avoid excessive synchronization(避免过度同步)
- Item 80: Prefer executors, tasks, and streams to threads(Executor、task、流优于直接使用线程)
- Item 81: Prefer concurrency utilities to wait and notify(并发实用工具优于 wait 和 notify)
- Item 82: Document thread safety(文档应包含线程安全属性)
- Item 83: Use lazy initialization judiciously(明智地使用延迟初始化)
- Item 84: Don’t depend on the thread scheduler(不要依赖线程调度器)
- Chapter 12. Serialization(序列化)
- Item 85: Prefer alternatives to Java serialization(优先选择 Java 序列化的替代方案)
- Item 86: Implement Serializable with great caution(非常谨慎地实现 Serializable)
- Item 87: Consider using a custom serialized form(考虑使用自定义序列化形式)
- Item 88: Write readObject methods defensively(防御性地编写 readObject 方法)
- Item 89: For instance control, prefer enum types to readResolve(对于实例控制,枚举类型优于 readResolve)
- Item 90: Consider serialization proxies instead of serialized instances(考虑以序列化代理代替序列化实例)