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

来源:互联网 发布:深圳软件产业基地地铁 编辑:程序博客网 时间:2024/06/05 06:11

一般来说,最好能重用对象而不是每次需要的时候就创建一个相同功能的新对象。重用的方式即快速,又流行。如果对象是不可变得,它就是种被重用。
String s = new String(“stringette”);
该语句每次被执行的时候都创建一个新的String实例,但是这些创建对象的动作全部是不必要的。

改进后的版本:
String s = “stringette”;
这个版本只用了一个String实例,而不是每次执行的时候都创建一个新的实例。而且,它还可以保证,对于所有在同一台虚拟机中运行的代码,只要它们包含相同字符创字面常量,该对象就会被重用。

除了重用不可变的对象外,也可以重用哪些已知不会被修改的可变对象。线面是一个比较微妙、也比较常见的反面例子。其中涉及可变的Date对象,他们的值一旦计算出来之后就就不在变化。这个类简历了一个模型:其中有一个人,并有一个isBabyBoomer方法,用来检验这个人时候为一个“baby booemr(生育高峰期出生的小孩)”,换句话说,就是检验这个人是否出生1946年至1964年期间。
class Person {
private Date birthDate;

    public boolean isBabyBoomer() {        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);        Date boomStart = gmtCal.getTime();        gmtCal.set(1956, Calendar.JANUARY, 1, 0, 0, 0);        Date boomEnd = gmtCal.getTime();        return birthDate.compareTo(boomStart) >= 0                && birthDate.compareTo(boomEnd) < 0;    }}

缺点:

isBabyBoomer每次被调用的时候,都会创建一个Calendar,一个TimeZone和两个Date实例,这是不必要的。

优化:

用了一个静态的初始化器(initializer),避免了这种效率低下的情况

class Person_1 {    private 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(1956, Calendar.JANUARY, 1, 0, 0, 0);        BOOM_END = gmtCal.getTime();    }    public boolean isBabyBoomer() {        return birthDate.compareTo(BOOM_START) >= 0                && birthDate.compareTo(BOOM_END) < 0;    }}

优点:

改进后的Person类只在初始化的时候创建Calendar、TimeZone和Date实例一次,而不是在每次调用isBabyBoomer的时候都创建这些事例。如果isBabyBoomer方法被频繁地调用,这种方法将会显著地提高性能。在我的机器上,每调用一千万次,原来的版本需要32000ms,而改进后的版本只需要130ms,大约快了250倍。除了提高性能之外,代码的含义也更加清晰了。把boomStart和boomEnd从局部变量改为final静态域,这些日期显然被作为常量对待,从而使得代码更易于理解。但是这种优化带来的效果并不总是那么明显,因为Calendar实例的创建代价特别贵。

2 0