《Effective Java》阅读笔记-第二章
Effective Java 阅读笔记
第二章 创建和销毁对象
第 1 条:用静态工厂方法代替构造器
静态工厂方法优势:
- 静态工厂方法有名称
静态工厂方法可以详细的指定名称,而使用构造器时如果没有文档会难以区分不同构造器之间的区别。
- 不必每次调用的时候创建一个新对象
静态工厂方法可以缓存预先构建好的实例,或者直接返回之前的实例(如果需要的话)。
- 可以返回任何类型的任何子类型对象
基于接口时,这会非常有用。既可以隐藏具体实现,又能返回需要的类型。
- 返回对象可以随着每次调用发生变化
EnumSet
类没有构造方法,只有静态方法,调用返回的时候会根据不同的枚举大小返回不同的内部类,而且以后也可以很好的新增或删除内部实现,这对调用者是不需要关心的。
- 返回对象可以暂时不存在
这个在服务提供框架(Service Provider Framework)中很有用,返回对象由服务提供者提供,框架不需要考虑是什么类型。
JDK在1.6的时候也提供了ServiceLoader
类,这是一个通用的服务提供处理。
静态工厂方法的缺点:
- 如果需要的类没有 public 构造器或者 protected 构造器,就不能子类话该类。
- 工厂类很难被发现
如果没有在API中明确注明,那么想实例化一个提供了工厂方法的类是比较难的。(深有同感)
静态工厂方法管用名称:
from
:类型转换方法,接受单个参数并返回对应类型。of
:聚合方法,接受多个参数,并合并成对应类型。valueOf
:比from
和of
更繁琐的替代方法。instance
或getInstance
:获取实例;create
或newInstance
:获取实例,并且保证每次都是一个新实例。get{Type}
:获取实例,主要用于工厂类和实例类型不一样时使用,比如Files.getFileStore(path)
new{Type}
:和get{Type}
类似,用于返回新实例,例如:Files.newBufferedReader(path)
{type}
:get{Type}
和new{Type}
的简化版,例如:Collections.list(...)
第 2 条 多个构造参数时有限考虑 Builder 建造器
工厂模式和构造器不能很好的扩展大量可选参数。
第 3 条 私有化构造器或者使用枚举类强化 Singleton 属性
单例可以使用饿汉、懒汉、双重检查锁、枚举来实现。
第 4 条 私有化构造器使类不可实例化
特指不要使用抽象类来禁止实例化。
第 5 条 优先考虑依赖注入来引入资源
能 DI 尽量 DI(依赖注入:Dependency Injection)。
第 6 条 避免创建不必要的对象
反例:String s = new String("blabla")
注意进行正则校验时,优先考虑创建公共的Pattern
对象,避免使用静态方法Pattern.matches()
,该静态方法每次都会创建一个Pattern
,并且Pattern
的创建是有一定负担的。
循环时优先使用基本类型,避免不必要的装箱。
第 7 条 消除过期的对象引用
给对象引用复制为 null 就可以消除引用,但是这里的消除引用并不是说局部变量用完之后赋值 null:
public void someMethod() {
List<String> strList = new ArrayList<>();
useStrMethod(strList);
// 并不是指这种
strList = null;
}
局部变量在方法结束时会自动解除引用,这里的过期引用特指缓存,否则很容易引发内存泄露。
比如在实现一个List时,内部使用数组缓存了对象,那个在调用removeLast方法时,不能仅仅把最大下标移动一下,而是要数组中引用的对象赋为null,这样删除的对象才能被GC。
第 8 条 避免使用终结方法(finalize)和清除方法(cleaner)
Object 上的 finalize 方法已经被标记为 removal,原本是被回收时会出发的方法,但是并不够保险,该方法现在已经被标记过时,不要使用。
cleaner 是 Java 9 加入的方法,加入的目的是代替finalize方法,这是一个使用例子:
Cleaner cleaner = Cleaner.create();
Cleaner.Cleanable cleanable = cleaner.register(anyObj, () -> {
System.out.println("do clean");
});
cleanable.clean();
不同的垃圾回收算法会在不同时间进行垃圾回收,因此程序不应该依赖这种方法,并且终结方法有严重性能损失。
正常应该使用 AutoCloseable 接口,然后使用 try-with-resource 的方式进行释放。
第 9 条 try-with-resource 优先于 try-finally
当有多个 io 流是,try-finally 的关闭会非常繁琐,并且可读性不好。如果一个类需要被关闭,那么就可以实现 AutoCloseable 接口,然后使用try-with-resource。