首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Effective Java 項目 5:避免創建不必要的對象

     編輯:Java 相關知識

引言

在 Java 程式設計中,重用現有物件而非重複創建功能相同的新物件,往往能帶來顯著的效能提升。特別是對於不可變物件,它們天生就適合被重複使用。本文將探討幾種常見的避免創建多餘物件的技巧。

善用靜態工廠方法重用不可變物件

許多不可變類別同時提供了建構子與靜態工廠方法。此時應優先選擇靜態工廠方法,因為它們不一定會在每次呼叫時都創建新實例。

Boolean b1 = Boolean.valueOf("test"); // 推薦:使用靜態工廠方法
Boolean b2 = new Boolean("test");     // 不推薦:每次都創建新物件

將不會被修改的可變物件提升為靜態常數

若某個方法會重複創建相同的可變物件(如 Calendar、TimeZone、Date),且這些物件在方法內部不會被修改,則應將其提取為靜態常數,僅在類別初始化時創建一次。

改進前:每次呼叫都創建新物件

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

改進後:靜態常數僅初始化一次

public class Person2 {
    private Date birthDate = new Date();
    private static final Date BOOM_START;
    private static final Date BOOM_END;
    static {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        calendar.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_START = calendar.getTime();
        calendar.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_END = calendar.getTime();
    }
    public boolean isBabyBoomer() {
        return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
    }
}

若 isBabyBoomer 方法被頻繁呼叫,改進後的版本能大幅降低物件創建開銷,顯著提升效能。

警惕自動裝箱與拆箱帶來的隱性物件創建

基本型別與其包裝類別之間的自動轉換(裝箱/拆箱)看似方便,實則可能在不知不覺中創建大量臨時物件。

public class Client {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Long sum = 0L; // 包裝類型
        for (long i = 0; i < Integer.MAX_VALUE; i++) {
            sum += i; // 每次迴圈都會觸發裝箱/拆箱,創建新的 Long 實例
        }
        long end = System.currentTimeMillis();
        System.out.println("Total spent time: " + (end - start) / 1000 + "s");
    }
}

上例中,將 sum 宣告為 Long 而非 long,導致每次累加都產生一個新的 Long 物件,嚴重拖慢執行速度。

結論

  • 優先使用基本型別而非包裝類別。
  • 善用靜態工廠方法重用不可變物件。
  • 將方法內重複創建且不被修改的可變物件提升為靜態常數。
  • 留意自動裝箱/拆箱,避免在熱點程式碼中使用包裝類型進行運算。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved