我正在研究有效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实例仅创建一次。Bloch解释说,如果isBabyBoomer()
频繁调用该方法,则可以显着提高性能。
在他的计算机上:
错误的版本:1000万次调用为32,000 ms
改进的版本:1000万次调用为130ms
但是,当我在系统上运行示例时,性能完全相同(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);
}
干杯,马库斯
您的基准测试是错误的。使用最新的Java 7和适当的预热,两种方法之间的区别非常大:
Person::main: estimatedSeconds 1 = '8,42'
Person::main: estimatedSeconds 2 = '0,01'
这是完整的可运行代码:
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Person {
private Date birthDate;
static Date BOOM_START;
static Date BOOM_END;
public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
}
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 isBabyBoomerWrong() {
// 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 boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0
&& birthDate.compareTo(BOOM_END) < 0;
}
public static void main(String[] args) {
Person p = new Person(new Date());
for (int i = 0; i < 10_000_000; i++) {
p.isBabyBoomerWrong();
p.isBabyBoomer();
}
long startTime = System.nanoTime();
for (int i = 0; i < 10_000_000; i++) {
p.isBabyBoomerWrong();
}
double estimatedSeconds = (System.nanoTime() - startTime) / 1000000000.0;
System.out.println(String.format("Person::main: estimatedSeconds 1 = '%.2f'", estimatedSeconds));
startTime = System.nanoTime();
for (int i = 0; i < 10_000_000; i++) {
p.isBabyBoomer();
}
estimatedSeconds = (System.nanoTime() - startTime) / 1000000000.0;
System.out.println(String.format("Person::main: estimatedSeconds 2 = '%.2f'", estimatedSeconds));
}
}
当用Jackson反序列化LocationGeneric时,我在Kotlin中遇到了以下问题。在这种情况下,我没有向用于构造具体类的抽象类添加额外信息。当我反序列化位置一或位置二时,它工作得很好。 这是我写的代码: 这是我遇到的错误: 无法构造的实例(尽管至少存在一个Creator):无法从Object值反序列化(没有基于委托或属性的Creator) 我尝试将抽象类更改为开放类,但到目前为止没有成
我在插入模板时遇到问题。当我运行tde时。templateInsert作为响应返回无效的权限,但我在数据库设置中启用了三重索引,并为用户添加了权限(添加了tde admin和tde view)。 我将逐步遵循本教程:https://developer.marklogic.com/learn/template-driven-extraction/ 这是整个错误消息: [javascript]SEC-
Oauth2,如下所示: 在访问回调url时,我得到以下异常: org.springframework.beans.factory.BeanCreationException:创建名为“ScopedTarget.oauth2ClientContext”的bean时出错:当前线程的作用域“session”不活动;如果您打算从单个对象引用这个bean,请考虑为它定义一个限定作用域的代理 完全异常跟踪:
我有一个简单的Java代码。目的是测试Java的enterLock()。有一个名为Bank的类(代码如下),它包含一个Account对象数组(Account类的代码如下)。 银行类可以使用名为“取款结束存款”的帐户对象的方法,将资金从一个帐户转移到另一个帐户。(其中一个数据成员是名为Accounts的帐户数组)。 AccountThread扩展将每个帐户作为线程运行的线程。它包含对“Bank”对象
NotificationActionReceiver: