- Effective Java Items about Creating and Destroying Objects
- Item1: Consider static factory methods instead of constructors
- Item2: Consider a builder when faced with many constructor parameters
- Item3: Enforce the singleton property with a private constructor or an enum
- Item4: Enforce noninstantiability with a private constructor
- Item5: Prefer dependency injection to hardwiring resources
- Item6: Avoid creating unnecessary objects
- Item7: Eliminate obsolete object references
- Item8: Avoid finalizers and cleaners
- Item9: Prefer try-with-resources to try-finally
Effective Java Items about Creating and Destroying Objects
Effective Java 书籍的这一章节主要讲了一些关于何时及如何创建对象,何时及如何避免创建对象,如何确保对象能够适时地被销毁及如何管理对象销毁之前必须进行的各种清理动作的建议。
Item1: Consider static factory methods instead of constructors
静态工厂方法相比构造器方法的几大优势如下:
1、静态工厂方法有名称,使得产生的客户端代码更容易阅读。
2、使用工厂方法不必在每次调用它们的时候都创建一个新对象。
3、静态工厂方法可以返回原返回类型的任何子类型的对象。这使得在选择返回的对象的类时有了更大的灵活性。
4、创建参数化类型实例的时候,静态工厂方法使得代码更加简洁。
然而静态工厂方法也有以下缺点需要注意:
1、类如果不含有public或者protected的构造器,其就不能被子类化。
2、静态工厂方法相对其他的静态方法实际上并没有任何区别。这使得对于提供了静态工厂方法而不是构造器的类来说,要想查明如何实例化一个类比较困难。
关于静态工厂方法可参考:
Java 设计模式——工厂模式
Item2: Consider a builder when faced with many constructor parameters
如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是种不错的选择,特别是当大多数参数都是可以选择的时候。与使用传统的重叠构造器模式相比,使用Builder模式的客户端代码将更易于阅读和编写,构建器也更加安全。
关于Builder模式可参考:
Java设计模式(二)——建造者模式
Builder Pattern in Java
effective java creating and destroying objects
Item3: Enforce the singleton property with a private constructor or an enum
可以利用私有属性或者枚举类型来强化单例属性。其中单元素的枚举类型已经成为实现单例模式的最佳方法,需要注意的是,当单例类必须继承自一个非枚举类型时,不能使用这种方法。
有关单例模式可参考:
Java设计模式(一)——单例模式
Java Singleton Pattern
Item4: Enforce noninstantiability with a private constructor
对于一些只包含静态方法和静态域的类,我们不希望其被实例化,可以通过私有构造方法使得其不能被实例化。当然这种方法也有一定副作用,其使得一个类不能被子类化。因为子类需要调用超类的构造函数,而超类的构造函数却是私有的,并不能被子类调用。
Item5: Prefer dependency injection to hardwiring resources
不要使用单例或静态的实用类来实现一个类,该类依赖于一个或多个底层资源,这些资源的行为会影响类的行为,并且不让类直接创建这些资源。相反,将资源或工厂传递给构造方法(或静态工厂或builder模式)。这种称为依赖注入的实践将极大地增强类的灵活性、可重用性和可测试性。
Item6: Avoid creating unnecessary objects
可以通过以下一些方法来避免创建不必要的对象:
1、重用不可变对象而不是每次需要的时候创建一个相同功能的新对象。
2、对于同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器并以此来避免创建不必要的对象。
3、也可以重用那些已知不会被修改的可变对象。
4、优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
5、避免创建不必要的对象并不是意味着“创建对象的代价很昂贵,而我们要尽可能避免创建对象”。事实上,针对小对象的创建和回收是非常廉价的。有时候,可以通过创建附加的对象从而使得程序更清晰简洁。
Item7: Eliminate obsolete object references
过期引用指的是永远也不会再被解除的引用。在Java这类支持垃圾回收的语言中,如果一个对象引用被无意识地保留起来了,那么垃圾回收机制不仅不会处理这个对象,而且连被这个对象所引用的其它对象也不会被处理。这样即便只有少量的几个对象引用被无意识保留下来,也会有许多对象被排除在垃圾回收机制之外,对性能造成潜在的重大影响。那如何解决这类问题?只需要在知道对象引用过期时,及时清空引用。只要是自己管理内存,就应该时时警惕内存泄漏问题。
内存泄漏的常见来源有:无意识的对象保持;缓存;监听器和其他回调。
Item8: Avoid finalizers and cleaners
终结方法是不可预测的,常常是危险而且不必要的。Java9已经弃用了终结方法,但是许多Java库中还用着这种方法。Java9中用Cleaners代替了终结方法。Cleaners比终结方法稍安全,但是仍然不可预测,慢和不必要。
Finalizers和cleaners的缺点之一是它们不能保证被及时执行。注重时间的任务不应该由终结方法和清理方法来完成。不但不能保证终结方法和清理方法能够及时执行,甚至其能不能执行也不会有保证。所以,永远不能依赖终结方法和清理方法来更新持久状态。
使用终结方法和清理方法会有严重的性能损失。显式的终结方法通常与try-finally 结构结合起来使用,以确保及时终止。重要的准则是:除非是作为安全网,或者是为了终止非关键的本地资源,否则请不要使用终结方法和清理方法。
Item9: Prefer try-with-resources to try-finally
操作一些必须被关闭的资源时,最好使用try-with-resources块而不是try-finally代码块,这样代码更短更清晰,而且生成的异常更有用。try-with-resources块使得正确编写操作必须关闭的资源的代码更加容易。
参考
Effective Java, Third Edition -Bloch-2017
林本托的博客