目录
第2章 创建和销毁对象
第1条:用静态工厂方法替代构造器
第2条:遇到多个构造器参数时要考虑使用构建器
例子
使用
第3条:用私有构造器或者枚举类型强化Singleton属性
例子
使用
第4条:通过私有构造器强化不可实例化的能力
第5条:优先考虑依赖注入来引用资源
第6条:避免创建不必要的对象
例子
第7条:消除过期的对象引用
第8条:避免使用终结方法和清楚方法
第9条:try-with-resources优先于try-finally
第3章 对于所有对象都通用的方法
第10条:覆盖equals时请遵守通用约定
第11条:覆盖equals时总要覆盖hashCode
第12条:始终要覆盖toString
第13条:谨慎地覆盖clone
第14条:考虑实现Comparable接口
第4章 类和接口
第15条:使类和成员的可访问性最小化
第16条:要在公有类而非公有域中使用访问方法
第17条:使可变性最小化
第18条:复合优于继承
第19条:要么设计继承并提供文档说明,要么禁止继承
第20条:接口优于抽象类
第21条:为后代设计接口
第22条:接口只用于定义类型
第23条:类层次优于标签类
第24条:静态成员类优于非静态成员类
第25条:限制源文件为单个顶级类
第5章 泛型
第26条:请不要使用原生态类型
第27条:消除非受检的警告
第28条:列表优于数组
第29条:优先考虑泛型
第30条:优先考虑泛型方法
第31条:利用有限制通配符来提升API的灵活性
第32条:谨慎并用泛型和可变参数
第33条:优先考虑类型安全的异构容器
第6章 枚举和注解
第34条:用enum替代int常量
第35条:用实例域代替序数
第36条:用EnumSet代替位域
使用EnumSet代替
第37条:用EnumMap代替序数索引
第38条:用接口模拟可扩展的枚举
第39条:注解优先于命名模式
第40条:坚持使用Override注解
第41条:用标记接口定义类型
第6章 Lambda和Stream
第42条:lambda优先于匿名类
第43条:方法引用优先于lambda
第44条:坚持使用标准的函数接口
第45条:谨慎使用Stream
第46条:优先选择Stream中无副作用的函数
第47条:Stream要优先用Collection作为返回类型
第48条:谨慎使用Stream并行
第2章 创建和销毁对象
第1条:用静态工厂方法替代构造器
- 有名称
- 不用每次调用都创建对象
- 可以返回原类型的子类型
第2条:遇到多个构造器参数时要考虑使用构建器
例子
public class Human {
private String name;
private int age;
private String id;
private Human(Builder builder) {
name = builder.name;
age = builder.age;
id = builder.id;
}
public static class Builder {
private String name;
private int age = 20;
private String id;
public Builder name(String name) {
this.name = name;
}
public Builder age(int age) {
this.age = age;
}
public Builder id(String id) {
this.id = id;
}
public Human build() {
return new Human(this);
}
}
}
使用
Human.Builder builder = new Human.Builder();
Human human = builder.name("lili").id("123456").build();
第3条:用私有构造器或者枚举类型强化Singleton属性
例子
public enum Singleton {
INSTANCE;
public int func() {
...
}
}
使用
int a = Singletion.INSTANCE.func();
单元素的枚举类型经常成为实现Singleton的最佳方法
- 提供了序列化机制
- 绝对防止多次实例化
但如果Singleton必须扩展一个超类(非Enum时),这种方法不适用。
第4条:通过私有构造器强化不可实例化的能力
例如工具类。
第5条:优先考虑依赖注入来引用资源
第6条:避免创建不必要的对象
例子
String s = new String("bob");
传递给String构造器的"bob"本身就是一个String实例。
要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
第7条:消除过期的对象引用
清空对象引用应该是一个例外,而不是一种规范行为。
第8条:避免使用终结方法和清楚方法
第9条:try-with-resources优先于try-finally
第3章 对于所有对象都通用的方法
第10条:覆盖equals时请遵守通用约定
- 自反性
- 对称性
- 传递性
- 一致性
- 对任何非null的引用x,x.equals(null)必须返回false
第11条:覆盖equals时总要覆盖hashCode
第12条:始终要覆盖toString
第13条:谨慎地覆盖clone
第14条:考虑实现Comparable接口
实现该接口就表明它的实例具有内在的排序关系。
第4章 类和接口
第15条:使类和成员的可访问性最小化
第16条:要在公有类而非公有域中使用访问方法
然而,如果类是包级私有的,或者是私有的嵌套类,直接暴露它的数据域并没有本质的错误。
第17条:使可变性最小化
使类成为不可变,要遵循下面五条规则:
- 不要提供任何会修改对象状态的方法
- 保证类不会被扩展(一般做法是声明类为final)
- 声明所有的域都是final
- 声明所有的域都为private
- 确保对于任何可变组件的互斥访问 如果类具有指向可变对象的域,则必须确保类的使用者无法获得这些对象的引用
public final class FinalClass {
private final double id;
private final String name;
public FinalClass(double id, String name) {
this.id = id;
this.name = name;
}
public String info() {
return name + id;
}
}
不可变对象本质上是线程安全的,它们不要求同步。
当多个线程并发访问这样的对象时,它们不会遭到破坏。
不可变类真正唯一的缺点是,对于每个不同的值都需要一个单独的对象。
第18条:复合优于继承
继承打破了封装性
第19条:要么设计继承并提供文档说明,要么禁止继承
第20条:接口优于抽象类
接口是定义mixin(混合类型)的理想选择。
第21条:为后代设计接口
第22条:接口只用于定义类型
第23条:类层次优于标签类
第24条:静态成员类优于非静态成员类
第25条:限制源文件为单个顶级类
第5章 泛型
第26条:请不要使用原生态类型
第27条:消除非受检的警告
第28条:列表优于数组
第29条:优先考虑泛型
第30条:优先考虑泛型方法
第31条:利用有限制通配符来提升API的灵活性
第32条:谨慎并用泛型和可变参数
第33条:优先考虑类型安全的异构容器
第6章 枚举和注解
第34条:用enum替代int常量
每当需要一组固定常量,并且在编译时就知道其成员的时候,就应该使用枚举
第35条:用实例域代替序数
永远不要根据枚举的序数导出与它关联的值,而是要将它保存在一个实例域中。 例子
public enum EnumTest {
SOLO(1),DUET(2),TRIO(3);
private final int id;
EnumTest(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
第36条:用EnumSet代替位域
public class Text {
public static final int STYLE_BOLD = 1 << 0; // 1
public static final int STYLE_ITALIC = 1 << 1; // 2
public static final int STYLE_UNDERLINE = 1 << 2; // 4
public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8
public void apply(int style) {
...
}
}
使用时
text.apply(STYLE_BOLD | STYLE_ITALIC);
上述定义在类Text的成员STYLE_BOLD等称作位域。
使用EnumSet代替
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE,STRIKETHROUGH}
public void apply(Set<Style> styleSet) {
...
}
}
使用时
text.apply(EnumSet.of(Style.BOLD, Style.ITALIC));
第37条:用EnumMap代替序数索引
第38条:用接口模拟可扩展的枚举
第39条:注解优先于命名模式
第40条:坚持使用Override注解
第41条:用标记接口定义类型
第6章 Lambda和Stream
第42条:lambda优先于匿名类
第43条:方法引用优先于lambda
例如
manlist.stream().forEach(System.out::println());
第44条:坚持使用标准的函数接口
6个基础函数接口:
![1602838537165](.assets/Effective Java(第3版) 90条经验法则/1602838537165.png)
第45条:谨慎使用Stream
通常不建议在Stream上调用parallel,使其并发执行。 如果实在不确定用Stream还是用迭代比较好,那么就两种都试试,看看哪一种更好用吧。