创建和销毁对象

第 1 条 : 考虑使用静态工厂方法替代构造方法

静态工厂方法实例

public static Boolean valueOf(boolean b) { 
return b ? Boolean.TRUE : Boolean.FALSE;
}

静态工厂方法的优点:

  • 有方法名,比构造方法更加容易理解
  • 不用重复创建新对象
  • 可以返回子类型
  • 返回对象的类可以根据输入参数的不同而不同
  • 静态方法更适于做服务型接口

静态工厂方法的缺点:

  • 可能无法被子类实例化(私有的构造器)
  • 不利于检索(比较难找到对应代码)

第2条:当构造方法参数过多时使用 builder 模式

可选参数比较多时,可用下面几种方法

  1. 可伸缩构造方法模式,但是当有很多参数时,很难编写,并读懂它。
  2. 使用javaBean模式,通过setter方法设置参数,但构造变得困难,而且变得不安全
  3. Builder模式,不直接生成对象,而是先得到builder对象,通过builder的类似setter方法设置参数,最后调用build方法生成不可变对象

缺点:Builder 模式比重叠构造器更冗长,只在参数很多的时候才使用,比如四个或者更多。

Builder方法实例

// Builder Pattern 
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;

public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;

// Optional parameters - initialized to default values
private int calories
private int fat
private int sodium= 0; = 0; = 0;
private int carbohydrate = 0;

public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}

public Builder calories(int val) {
calories = val;
return this;
}

public Builder fat(int val) {
fat = val;
return this;
}

public Builder sodium(int val) {
sodium = val;
return this;
}

public Builder carbohydrate(int val) {
carbohydrate = val; return this;
}

public NutritionFacts build() {
return new NutritionFacts(this);
}
}

private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate
}
}

第3条:使用私有构造方法或枚举类实现 Singleton 属 性

Java 1.5 之前,实现单例是通过“构造器私有化,静态公有 final 实例对象”,或直接获取,或通过方法获取。

Java 1.5 之后,实现单例的最佳方法,是编写“单元素的枚举”类型:

public enum Elvis {
INSTANCE;
public void whateverMethod() { ... }
}

无偿提供序列化,防止多次实例化。

第4条:使用私有构造器执行非实例化

一些工具类不希望被实例化,将构造函数私有,避免外部调用,并在构造函数中抛异常,避免内部调用。

第5条:依赖注入优于硬连接资源(hardwiring resources)

行为参数化是依赖注入的有用变体,将Lexicon dictionary作为参数,相对硬编码更加灵活。

对于行为参数化的类,可以通过策略模式和lambda表达式灵活实现

第6条:避免创建不必要的对象

最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。如果对象是不可变的,它就始终可以被重用。

优先使用基本类型而不是装箱基本类型,当心无意识的自动装箱,比如:下面这个程序会有大量装箱成Long

Long sum = 0
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;

使用 Byte.valueOf 来创建包装类型,因为 -128~127 的数会缓存起来,要从缓冲池中取,Short、Integer、Long 也是这样。

第 7 条:消除过期的对象引用

不需要对所有对象显式置空,以下情形考虑资源手工处理:

  • 类是自己管理内存,如例子中的 Stack 类。
  • 使用对象缓存机制时,需要考虑被从缓存中换出的对象,或是长期不会被访问到的对象。
  • 事件监听器和相关回调。使用弱引用

第 8 条:避免使用终结方法

finalizer 不保证会被及时的执行,甚至不一定执行。

除非是作为安全网,或者为终止非关键的本地资源,否则请不要使用终结方法。

第 9 条: 用 try-with-resources 代替 try-finally

实现 AutoCloseable 接口的类应使用 try-with-resources,因其可同时处理多个资源,不用嵌套

Author: iMine
Link: https://imine141.github.io/2020/07/24/Effective%20java/%E5%88%9B%E5%BB%BA%E5%92%8C%E9%94%80%E6%AF%81%E5%AF%B9%E8%B1%A1/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.