重用不可变对象
一般来说, 最好能重用对象, 而不是在每次需要的时候创建一个相同功能的新对象.
重用:快速,流行
新建:慢,浪费存储.
反向示例
String str = new String("stringette"); //DON'T DO THIS
"stringette" 本身就是String实例.
正向示例:
String str = "stringette";
选择静态工厂方法而不是构造器
当一个不可变类同时提供静态工厂方法和构造器时,通常可以选择静态工厂方法而不是构造器,以避免创建不必要的对象.
- 构造器: 一般是创建一个新的对象, Boolean(String)
- 静态工厂方法:一般是返回已有对象,例如 Boolean.valueOf(Stirng)
重用已知不会被修改的可变对象\
不要这么做:
public class Person {
private final Date birthDate;
...
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
** 应该这么做:**
public class Person() {
private final Date birthDate;
...
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
}
}
优先使用基本类型,而不是装箱基本类型, 要当心无意识的自动装箱
Java 1.5版本中, 实现自动装箱(autoboxing),允许将基本类型和装箱基本类型混用.,按需自动装箱和拆箱.
不要这么做:
// Slow program. Where is the object creation?
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
sum的声明是Long
,而不是 long
, 这样意味着程序构造了大约2^31个多余的Long实例.
- Effective Java 第5条:当你应该重用现有对象的时候,请不要创建新的对象.(代码风格和性能)
- Effective Java 第39条(defensive copying保护性拷贝): 当你应该创建新的对象的时候,请不要重用现有的对象.(潜在的错误和安全漏洞)
考虑点: 使用重用对象要付出的代价 VS 创建重复对象的代价
例如遍历列表的同时处理列表中的元素,这时重用现有对象可能会导致代码错误. 而创建重复对象的代价仅仅是影响程序的风格和性能.