第五條:避免創建不必要的對象

一般來說,我們最好能夠重用對象,而不是每次需要的時候都去創建一個相同的對象。

重用對象即快速,又流行,如果對象時不可變的,它就始終可以被重用。

下面有一個反面的例子:

String s=new String("string");

該語句每次被執行都會創建一個新的String實例,但是這是不必要的,傳遞給String構造器的參數本身就是一個String實例,

功能方面等同於構造器創建的所有對象,如果這是一個被頻繁調用的方法中,就會創建出成千上萬不必要的String實例。

可以改進爲如下所示:

String s="String";

除了重用不可變的對象之外,也可以重用那些已知不會被修改的可變對象。

下面是一個反面的例子:

public 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(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 class Person {
    private static  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;
    }
}

改進後的代碼,只有在第一次初始化的時候纔會去創建需要的實例。

如果isBabyBoomer方法永遠不被調用,那就沒有必要初始化那些BOOM_START和BOOM_END,

我們可以通過延遲加載,來避免這個問題,把BOOT_START和BOOM_END的初始化,放在第一次調用isBabyBoomer方法的時候進行。

在JAVA1.5的髮型版本中,加入了自動裝箱拆箱,如果不小心使用,也會導致創建不必要的對象,如下:

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,就意味着要創建大約2的32次方個多餘的Long實例,所以導致了導致了計算較慢,如果把Long改成long就會快很多了。
發佈了25 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章