effectiveJava

Effective Java Item53 - 慎用可變參數

這篇是Effective Java - Use varargs Judiciously章節的讀書筆記 本篇的程式碼來自於原書內容

Item53: 慎用可變參數

可變參數是java 1.5引進的方法 它可以讓你的方法吃進任意數量(0至多個)的同類型的變數

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

這個解法有兩個問題

如果客戶真的沒丟參數進去 你的方法無法在編譯期被偵測 只能在運行期被動的丟例外

第二個問題 很不美觀 除非將min初始化為Integer.MAX_VALUE 否則無法使用for-each

比較好的方法 就是先寫死一個 之後再用可變參數

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

這樣就從0個以上 變成 1個以上

其實java把可變參數引進來 最大的用途是為了反射 想了解更多反射的細節 請關注一本2019年出版即將改變java生態的書 這裡就先不談反射

性能

可變參數雖然好用 但性能卻很差 每次可變參數的方法被呼叫 都需要配置一個數組並且對每個元素初始化 身為專業的程序員 要能夠了解你的use case進而最佳化

假設95%的use case都是只有四個參數以下 你可以單獨宣告這四個方法

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) { }

總結

對於參數數目不定的方法 可以使用可變參數 但是性能不佳 可以的話做一些最佳化