Effective Java 第三版——53. 明智而審慎地使用可變參數

Tips
書中的源代碼地址:https://github.com/jbloch/effective-java-3e-source-code
注意,書中的有些代碼裏方法是基於Java 9 API中的,因此JDK 最好下載 JDK 9以上的版本。java

Effective Java, Third Edition

53. 明智而審慎地使用可變參數

可變參數方法正式名稱稱爲可變的參數數量方法『variable arity methods』 [JLS, 8.4.1],接受零個或多個指定類型的參數。 可變參數機制首先建立一個數組,其大小是在調用位置傳遞的參數數量,而後將參數值放入數組中,最後將數組傳遞給方法。git

例如,這裏有一個可變參數方法,它接受一系列int類型的參數並返回它們的總和。如你所料,sum(1,2,3)的值爲6,sum()的值爲0:github

// Simple use of varargs

static int sum(int... args) {
    int sum = 0;
    for (int arg : args)
        sum += arg;
    return sum;
}

有時,編寫一個須要某種類型的一個或多個參數的方法是合適的,而不是零或更多。 例如,假設要編寫一個計算其多個參數最小值的方法。 若是客戶端不傳遞任何參數,則此方法定義不明確。 你能夠在運行時檢查數組長度:數組

// The WRONG way to use varargs to pass one or more arguments!

static int min(int... args) {
    if (args.length == 0)
        throw new IllegalArgumentException("Too few arguments");
    int min = args[0];
    for (int i = 1; i < args.length; i++)
        if (args[i] < min)
            min = args[i];
    return min;
}

該解決方案存在幾個問題。 最嚴重的是,若是客戶端在沒有參數的狀況下調用此方法,則它在運行時而不是在編譯時失敗。 另外一個問題是它很難看。 必須在args參數上包含顯式有效性檢查,除非將min初始化爲Integer.MAX_VALUE,不然不能使用for-each循環,這也很難看。性能優化

幸運的是,有一種更好的方法能夠達到預期的效果。 聲明方法採用兩個參數,一個指定類型的普通參數,另外一個此類型的可變參數。 該解決方案糾正了前一個示例的全部缺陷:性能

// The right way to use varargs to pass one or more arguments

static int min(int firstArg, int... remainingArgs) {
    int min = firstArg;
    for (int arg : remainingArgs)
        if (arg < min)
            min = arg;
    return min;
}

從這個例子中能夠看出,在須要參數數量可變的方法時,可變參數是有效的。可變參數是爲printf方法而設計的,該方法與可變參數同時添加到Java 平臺中,以及包括通過改造的核心反射機制。printf和反射機制都從可變參數中受益不淺。優化

在性能關鍵的狀況下使用可變參數時要當心。每次調用可變參數方法都會致使數組分配和初始化。若是你從經驗上肯定負擔不起這個成本,可是還須要可變參數的靈活性,那麼有一種模式可讓你魚與熊掌兼得。假設你已肯定95%的調用是三個或更少的參數的方法,那麼聲明該方法的五個重載。每一個重載方法包含0到3個普通參數,當參數數量超過3個時,使用一個可變參數方法:設計

public void foo() { }

public void foo(int a1) { }

public void foo(int a1, int a2) { }

public void foo(int a1, int a2, int a3) { }

public void foo(int a1, int a2, int a3, int... rest) { }

如今你知道,在全部參數數量超過3個的方法調用中,只有5%的調用須要支付建立數組的成本。與大多數性能優化同樣,這種技術一般不太合適,但一旦真正須要的時候,它是一個救星。rest

EnumSet的靜態工廠使用這種技術將建立枚舉集合的成本降到最低。這是適當的,由於枚舉集合爲比特屬性提供具備性能競爭力的替換(performance-competitive replacement for bit fields)是相當重要的(條目 36)。code

總之,當須要使用可變數量的參數定義方法時,可變參數很是有用。 在使用可變參數前加上任何須需的參數,並注意使用可變參數的性能後果。

相關文章
相關標籤/搜索