本书旨在帮助你高效地使用 Java 及其基础类库:java.lang,java.util 和 java.io 及其子包下的诸如 java.util.concurrent 和 java.util.function。其它的库也会不时地讨论一下。
本书共由 90 个条目组成,每一条都传达了一条规则。这些规则反映了最有经验的优秀程序员在实践中常用的一些有益做法。这些条目被松散地分为了 11 个章节,每个章节都传达了软件设计广泛的一面。各个条目间或多或少保持独立,不需要刻意地将本书从头读到尾。条目间在很大程度上相互引用,所以你可以很容易地通过本书规划自己的路线。
自上一版书发布以来,该平台增加了很多新的特性。本书中的很多条目以一定的方式使用了这些特性,下面这张表展示了这些关键特性所在的主要范围:
特性 | 所在条目 | 发行版本 |
---|---|---|
Lambdas | 第 42 ~ 44 条 | Java 8 |
Streams | 第 45 ~ 48 条 | Java 8 |
Optionals | 第 55 条 | Java 8 |
接口默认方法 | 第 21 条 | Java 8 |
try-with-resources 语句 | 第 9 条 | Java 7 |
@SafeVarargs | 第 32 条 | Java 7 |
模块化 | 第 15 条 | Java 9 |
大多数条目都通过程序示例进行说明。本书的一个主要特点是,它包含了很多描述设计模式(Design Patterns)和习惯用法(Idioms)的代码示例。在恰当的地方,还为这些设计模式和习惯用法交叉引用至该领域的标准参考书 [Gamma95]。
许多条目都包含了一个或多个应该在实践中避免的程序示例。像这样的例子,有时候被认为是“反模式”(Antipatterns),其被清晰的标注了 //Never do this!
。在每种情况中,条目都解释了为什么这个示例是不好的,并且提供了解决的方法。
本书不是面向初学者的:本书假设你已经熟悉 Java 了。如果你还没有,可以考虑一本不错的入门书籍,比如 Peter Sestoft 的 Java Precisely Sestoft16。既然 Effective Java 旨在让任何具有 Java 语言知识的人都可以使用,那它也应该为高级程序员提供精神食粮。
本书中大多数规则都是从少数的几条原则推导出来的。清晰和简洁至关重要。组件的使用者不应该对组件的表现行为感到疑惑。组件应该尽可能的小,但又不能太小(本书中所使用的术语“组件”(component),是指任何可重用的软件元素,从单个方法到由多个包组成的复杂框架都可以是一个组件)。代码应该是被重用,而不是被拷贝。组件之间的依赖性应该保持在最低限度。出现错误应尽可能被检测到,最理想的就是在编译期。
虽然本书中的规则并不会百分之百的适用任何场景,但是,它们的确体现了绝大部分场景的最佳编程实践。你不应该亦步亦趋地遵从这些规则,而应该只是偶尔并且具有合理理由的情况下才违反这些规则。同大多数学科一样,学习编程的艺术,首先要学习它的规则,然后才学习何时打破它们。
本书的大部分内容不是在讨论性能如何,而是在讨论如何写出清晰,正确,可用,健壮,灵活和可维护的代码。如果你能做到这些,那么获得所需要的的性能就是一件相对简单的事情了(见第 67 条)。一些条目的确讨论了性能问题,并且有的还提供了性能指标。这些性能指标都被标明了“在我的机器上(On my machine)”,所以应该把这些指标当作是近似值。
值得提及的是,我(指作者)的机器是一台老旧的自制电脑,主机为 3.5 GHz 四核英特尔酷睿 i7-4770K,配备 16G 的 DDR3-1866 CL9 内存,在 Microsoft Windows 7 Professional SPI (64位)操作系统上运行 Azul's Zulu 9.0.0.15 发行版本的 OpenJDK。
当讨论 Java 编程语言的特性及其类库时,有时候必须要指明具体的发行版本。为了简便起见,本书使用昵称而不是官方的发行名称,这张表展示了发行名称和昵称的对应关系:
官方发行名称 | 昵称 |
---|---|
JDK 1.0.x | Java 1.0 |
JDK 1.1.x | Java 1.1 |
Java 2 Platform, Standard Edition, v1.2 | Java 2 |
Java 2 Platform, Standard Edition, v1.3 | Java 3 |
Java 2 Platform, Standard Edition, v1.4 | Java 4 |
Java 2 Platform, Standard Edition, v5.0 | Java 5 |
Java Platform, Standard Edition 6 | Java 6 |
Java Platform, Standard Edition 7 | Java 7 |
Java Platform, Standard Edition 8 | Java 8 |
Java Platform, Standard Edition 9 | Java 9 |
尽管这些例子相当完整,但是可读性要高于完整性。它们直接使用了 java.util 和 java.io 中的类,为了编译示例,你可能需要添加一行甚至多行 import 语句。本书的网站 http://joshblock.com/effectivejava,包含了每个示例的完整版本,你可以直接编译运行它们。
在大多数情况下,本书使用了《The Java Language Specification,Java SE 8 Edition》[JLS] 中定义的技术术语。这其中有一些术语值得特别提及。Java 语言支持 4 种类型:接口(包括注解)、类(包括枚举)、数组和基本类型(primitive),前面 3 种被称为引用类型(reference type),类实例和数组是对象(object),而基本类型的值则不是。类的成员(member)由属性,方法,成员类和成员接口组成。方法的签名(signature)是由它的名称和形式参数类型组成,签名不包含方法的返回类型。
本书也使用了一些与 《The Java Language Specification》 不同的术语。与 《The Java Language Specification》不同的是,本书用术语“继承(inheritance)”作为“子类化(subclassing)”的同义词。本书不再使用“接口继承”这个术语,而是简单地描述为一个类实现(implement)了一个接口,或者一个接口扩展(extend)了另一个接口。为了描述“在没有指定访问级别的情况下所使用的访问级别”,本书使用了传统的“包级私有(package-private)”而不是在 [JLS, 6.6.1] 中技术上正确的 “包访问(package-access)”。
本书也使用了一些在《The Java Language Specification》 中没有定义的技术术语。术语“导出的 API (exported API)”,或者简单地说 API ,是指类、接口、构造器(constructor)、成员和序列化形式(serialized form),程序员通过它们可以访问类、接口或者包。(术语 API 是 Application Programming Interface 的简写,这里之所以使用 API 而不用接口(interface),是为了不与 Java 语言中的 interface 类型混淆)。使用 API 编写程序的程序员被称为该 API 的用户(user),使用 API 实现的类被称为是该 API 的客户(client)。
类、接口、构造器、成员和序列化形式被统称为 API 元素(API element)。导出的 API 由可在定义该 API 的包之外访问的 API 元素组成。任何客户端都可以使用这些 API 元素,API 的作者则负责支持这些 API 元素。并非巧合的是,Javadoc 工具类在默认操作模式下正是为这些元素生成文档。不严格地讲,一个包的导出 API 由该包中每个公有类或者接口中的公有(public)成员和受保护的(protected)成员以及构造器组成。
在 Java 9 中,模块系统加入到了这个平台。如果一个库使用了模块系统,那么其导出的 API 就是库的模块声明导出的所有包的导出 API 的并集。
[Gamma95]
Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. 1995.
Design Patterns: Elements of Reusable Object-Oriented Software. Reading,
MA: Addison-Wesley. ISBN: 0201633612.
[Sestoft16]
Sestoft, Peter. 2016. Java Precisely, 3rd ed. Cambridge, MA: The MIT Press.
ISBN: 0262529076.
[JLS]
Gosling, James, Bill Joy, Guy Steele, and Gilad Bracha. 2014. The Java
Language Specification, Java SE 8 Edition. Boston: Addison-Wesley. ISBN:
013390069X.
翻译:Inno
校对:Angus