我正在学习有效的 Java,在本书的第 5 项中,Joshua Bloch 谈到了避免创建不必要的对象。一个示例演示了可变的 Date 对象,一旦它们的值被计算出来就永远不会被修改。
这里的“坏习惯”:
public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
}
// DON'T DO THIS!
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;
}
isBabyBoomer 方法在每次调用时都会不必要地创建一个新的 Calendar、TimeZone 和两个 Date 实例——这对我来说显然是有意义的。
这里是改进的代码:
public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
}
/**
* The starting and ending dates of the baby boom.
*/
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;
}
Calendar、TimeZone 和 Date 实例在初始化时只创建一次。isBabyBoomer()
Bloch 解释说,如果频繁调用该方法,这会显着提高性能。
在他的机器上:
错误版本:1000 万次调用需要 32,000 毫秒
改进版本:1000 万次调用需要 130毫秒
但是当我在我的系统上运行示例时,性能完全相同(14 毫秒)。这是实例只创建一次的编译器功能吗?
编辑:
这是我的基准:
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
cal.set(1960, Calendar.JANUARY, 1, 1, 1, 0);
Person p = new Person(cal.getTime());
long startTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
p.isBabyBoomer();
}
long stopTime = System.nanoTime();
long elapsedTime = stopTime - startTime;
double mseconds = (double) elapsedTime / 1000000.0;
System.out.println(mseconds);
}
干杯,马库斯