第5條 避免建立沒必要要的對象

一般來講,最好能重用對象而不是在每次須要的時候就建立一個相同功能的新對象。重用方式既快速、又流行。若是對象是不可變的(immutable),它始終能夠被重用。java

首先舉一個反面例子程序員

String result=new String("oschina");

該語句每執行一次就會建立一個String實例,若是這在一個循環中,將會有不少String實例被建立,有可能會建立成千上萬的實例,顯然這是沒必要要的。上面的代碼能夠這樣修改ide

String result="oschina";

這種寫法只用了一個String實例,而不是每次都建立一個實例。 這樣能夠保證,對於全部在同一臺虛擬機中運行的代碼,只要它們包含相同的字符串字面常量,該對象就會被重用。性能

其次,對於同時提供了靜態工廠方法和構造器的不可變類,一般能夠使用靜態工廠方法而不是構造器,以免建立沒必要要的對象。例如,靜態工廠方法Boolean.valueOf(String)幾乎老是優先於構造器Boolean(String)。構造器在每次被調用的時候都會建立一個新的對象,而靜態工廠方法則歷來不要求這樣作,實際上也不會這樣作。this

除了重用不可變的對象以外,也能夠重用那些已經不會被修改的可變對象。spa

反面例子code

public class Person {
   private final Date birthDate;

   public Person(Date birthDate) {
      // Defensive copy - see Item 39
      this.birthDate = new Date(birthDate.getTime());
   }

   // Other fields, methods omitted

   // 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實例,這顯然是沒必要要的。對象

對於上面的代碼能夠這樣修改字符串

class Person {
   private final Date birthDate;

   public Person(Date birthDate) {
      // Defensive copy - see Item 39
      this.birthDate = new Date(birthDate.getTime());
   }

   // Other fields, methods

   /**
    * 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;
   }

這樣把每次須要調用的變量放到static靜態塊裏面,這樣就保證了避免頻繁被調用的次數。從而使性能獲得提升。
get

在Java 1.5 的發行版本中,有一種建立多餘對象的新方法,稱做自動裝箱(autoboxing),它容許程序員將基本類型和裝箱基本類型混用,按需自動裝箱和拆箱。

public class Sum {
   // Hideously slow program! Can you spot the object creation?
   public static void main(String[] args) {
      LongTimes();
      longTimes();
   }

   public static void LongTimes(){
      long beginTime = System.currentTimeMillis();
      Long sum = 0L;
      for (long i = 0; i < Integer.MAX_VALUE; i++) {
         sum += i;
      }
      long endTime = System.currentTimeMillis();
      System.out.println("Long====總數:"+sum);
      System.out.println("Long====耗時:"+(endTime-beginTime)/1000);
   }


   public static void longTimes(){
      long beginTime = System.currentTimeMillis();
      long sum = 0L;
      for (long i = 0; i < Integer.MAX_VALUE; i++) {
         sum += i;
      }
      long endTime = System.currentTimeMillis();
      System.out.println("long====總數:"+sum);
      System.out.println("long====耗時:"+(endTime-beginTime)/1000);
   }

這種Long和long計算的結果以下,只由於將變量sum聲明爲Long而不是long,從而多計算了2*31次方,因此結論很明顯,要優先使用基本類型而不是自動封裝類型,要小心無心識的自動封裝。

相關文章
相關標籤/搜索