经典Jolt 获奖作品Effective Java的第3版,从Java 5 到Java 9的种种特性,Java 开发人员不可缺少的一本参考书:Effective Java中文版(原书第3版),2024全新译本,豆瓣原版评分9.6,中文版9.8。
作者约书亚.布洛克(Joshua Bloch)是美国卡内基-梅隆大学教授,曾是Google公司首席Java架构师、Sun公司杰出工程师和Transarc公司高级系统设计师。他带领团队设计和实现过无数的Java平台特性,包括JDK 5.0语言增强版和获奖的Java Collections Framework。他拥有哥伦比亚大学的计算机科学学士学位和卡内基-梅隆大学的计算机科学博士学位。
Effective Java中文版(原书第3版)
Effective Java是Java程序员必读的书目。经典Jolt 获奖作品Effective Java的第3 版,对上一版进行了全面更新,涵盖了 从Java 5 到Java 9的种种特性,是Java 开发人员不可缺少的一本参考书。包含90 个条目,形式简洁。每个条目都讲述了对Java的独到见解, 阐明了如何编写高效、优雅的程序,并且提供了清晰、易懂的示例代码。
本书增加了 Lambda表达式、流、Optional类、接口默认方法、 try-with-resources、@SafeVarargs注解、模块等Java 7 及后续版本所引入的新特性。本书介绍了如何充分利用泛型、枚举、注解、自动装箱、for-each 循环、可变参数、并发机制等各种特性,帮助读者更加有效地使用Java编程语言及其基本类库(java.lang、java.util和http://java.io),以及子包(如java.util.concurrent和java.util.function等)。
本书并非面向 Java 初学者,而是要求读者有一定的Java 编程经验。对在 Java 开发方 面已经积累一定经验的读者而言,本书可以帮助其更深入地理解 Java 编程语言,以成为更 高效、卓越的 Java 开发人员。
本书共包含 90 个条目,每个条目都会讨论一条规则。这些规则体现了优秀且有经 验的程序员通常会坚持的一些有益做法。本书将这些条目大致划分为 11 个章节,每个 章节会涉及软件设计的某个具体方面。因此, 不一定需要按部就班地从头到尾阅读,每 个条目基本都是独立的。这些条目之间有很多交叉引用,因此可以轻松地找到自己需要 的内容。
自本书的上一个版本出版以来,Java 平台又增加了很多新特性。本书中的大部分条目 都以某种方式使用了这些特性。表 1-1 列出了这些主要特性会在哪些条目中讲解。
表 1-1 主要特性对应的条目
特 性 | 条 目 | 发 行 版 本 |
Lambda 表达式 | 条目 42~44 | Java 8 |
Stream 流 | 条目 45~48 | Java 8 |
Optional 类 | 条目 55 | Java 8 |
接口默认方法 | 条目 21 | Java 8 |
try-with-resources | 条目 9 | Java 7 |
@SafeVarargs 注解 | 条目 32 | Java 7 |
Module 模块化 | 条目 15 | Java 9 |
大多数条目都会通过程序示例加以说明。本书有个突出的特点,就是包含了很多用来说明设计模式(Design Pattern)和习惯用法(Idiom)的代码示例。
许多条目还会包含一个或多个程序示例,用来说明在实践中应该避免的做法。这类例 子,有时被称为反模式(Antipattern),在注释中会被清楚地标注为“// 不要这样做!”。在 每一种情况下,对应的条目都会解释为什么这样做不好,并提供替代方案。
本书不适合初学者,而是假设读者已经熟悉 Java。如果你还不熟悉,可以考虑选择一 本优秀的 Java 入门书,如彼得 ·塞斯措夫特(Peter Sestoft)的 Java Precisely 。 本书适合任何有 Java 基本知识的人阅读,同时也能使高级程序员从中得到启发。
本书中的大多数规则都源于几条基本原则。清晰性和简洁性最为重要:组件的行为不能使用户感到意外。组件应该尽可能小,但也不能过小。①代码应该被复用,而不是被复制。 组件之间的依赖性应保持在最低限度。错误越早被检测出来越好,最好是在编译时就被发 现并解决。
虽然本书中的规则并不能百分之百适用于任何情况,但它们确实是绝大多数情况下的 最佳编程实践。你并不应该一味遵循这些规则,但是如果偶尔需要打破它们,也一定要有 充分的理由。学习编程的艺术,就像学习其他大多数学科一样,都是先学习规则,然后再 学习何时打破这些规则。
本书的大部分内容并不是讨论性能的,而是关注如何编写出清晰、正确、可用、健壮、 灵活和可维护的程序。如果能够编写出这样的程序,那么要得到所需要的性能,往往也就 比较简单了)。有些条目确实讨论了性能问题,有的还提供了性能数据。这些数 据,书中会加上“在我的机器上”这样的字样,因此最多只能将其视作近似值。
本书也使用了一些与《Java 语言规范:基于 Java SE 8》不同的术语。例如, 本书会将 继承(inheritance)用作子类化(subclassing)的同义词。本书没有对接口使用继承这一术 语,而是简单地表达为一个类实现(implement)了一个接口,或者一个接口扩展(extend) 了另一个接口。对于没有指定访问级别的情况,本书会使用传统的包私有(package-private) 这个术语,而没有使用技术上更严谨的包访问(package access )[JLS, 6.6.1]。
本书还使用了一些在《Java 语言规范:基于 Java SE 8》中没有定义的术语。术语导出 API(exported API),或者简单地说就是 API,指的是类、接口、构造器、成员以及序列化 形式(serialized form),程序员可以通过它们访问类、接口或者包。 使用 API 编写程序的程序员,称为该 API 的用户(user )。如果某个类的实现中用到了一个 API,则称该类为这 个 API 的客户端(client)。
类、接口、构造器、成员和序列化形式统称为 API 元素(API element)。导出 API 由 所有可在定义这个 API 的包之外访问的 API 元素构成。任何客户端都可以使用这些 API 元 素,而 API 的创建者负责支持它们。并非巧合的是,Javadoc 工具在其默认操作模式下生 成的文档中也会包含这些元素。笼统地讲,一个包的导出 API,是由该包中的每个公有(public)类或接口中公有的和受保护的(protected)成员及构造器组成的。
Java 9 向 Java 平台引入了模块系统(module system)。如果一个类库使用了模块系统, 其导出 API 就是该类库的模块声明导出的所有包的导出 API 的组合。
掌握90条编程法则让你成为优秀的java程序员
1:用静态工厂方法代替构造器
2:当构造器参数较多时考虑使用生成器
3:利用私有构造器或枚举类型强化Singleton属性 13
4:利用私有构造器防止类被实例化
5:优先考虑通过依赖注入来连接资源
6:避免创建不必要的对象
7:清除过期的对象引用
8:避免使用终结方法和清理方法
9:与try-finally相比,首选try-with-resources
10:在重写equals方法时要遵守通用约定
11:重写equals方法时应该总是重写hashCode方法
12:总是重写toString方法
13:谨慎重写clone方法
14:考虑实现Comparable接口
15:最小化类和成员的可访问性
16:在公有类中,使用访问器方法,而不使用公有的字段
17:使可变性最小化
18:组合优先于继承
19:要么为继承而设计并提供文档说明,要么就禁止继承
20:与抽象类相比,优先选择接口
21:为传诸后世而设计接口
22:接口仅用于定义类型
23:优先使用类层次结构而不是标记类
24:与非静态成员类相比,优先选择静态成员类
25:将源文件限制为单个顶层类
26:不要使用原始类型
27:消除unchecked类型的警告
28:列表优先于数组
29:首选泛型类型
30:首选泛型方法
31:使用有限制的通配符增加API的灵活性
32:谨慎混用泛型和可变参数
33:考虑类型安全的异构容器
34:使用enum代替int常量
35:使用实例字段代替序号
36:使用EnumSet代替位域
37:不要以序号作为索引,使用EnumMap代替
38:使用接口模拟可扩展的枚举
39:与命名模式相比首选注解
40:始终使用Override注解
41:使用标记接口来定义类型
42:与匿名类相比,优先选择Lambda表达式
43:与Lambda表达式相比,优先选择方法引用
44:首选标准的函数式接口
45:谨慎使用流
46:在流中首选没有副作用的函数
47:作为返回类型时,首选Collection而不是Stream
48:将流并行化时要谨慎
49:检查参数的有效性
50:必要时进行保护性复制
51:仔细设计方法签名
52:谨慎使用重载
53:谨慎使用可变参数
54:返回空的集合或数组,而不是null
55:谨慎返回Optional
56:为所有导出的API元素编写文档注释
57:最小化局部变量的作用域
58:与传统的for循环相比,首选for-each循环
59:了解并使用类库
60:如果需要精确的答案,避免使用float和double
61:首选基本类型,而不是其封装类
62:如果其他类型更适合,就不要使用字符串
63:注意字符串拼接操作的性能
64:通过接口来引用对象
65:与反射相比,首选接口
66:谨慎使用本地方法
67:谨慎进行优化
68:遵循普遍接受的命名惯例
69:异常机制应该仅用于异常的情况
70:对于可恢复的条件,使用检查型异常;对于编程错误,使用运行时异常
71:避免不必要地使用检查型异常
72:优先使用标准异常
73:抛出适合于当前抽象的异常
74:将每个方法抛出的所有异常都写在文档中
75:将故障记录信息包含在详细信息中
76:努力保持故障的原子性
77:不要忽略异常
78:同步对共享可变数据的访问
79:避免过度同步
80:与线程相比,首选执行器、任务和流
81:与wait和notify相比,首选高级并发工具
82:将线程安全性写在文档中
83:谨慎使用延迟初始化
84:不要依赖线程调度器
85:优先选择其他序列化替代方案
86:在实现Serializable接口时要特别谨慎
87:考虑使用自定义的序列化形式
88:保护性地编写readObject方法
89:对于实例受控的类,首选枚举类型而不是readResolve
90:考虑使用序列化代理代替序列化