В дополнение к другим отличным ответам здесь есть небольшое преимущество в производительности во время выполнения (в дополнение к избежанию выделения массива), заключающееся в том, что перегрузки с нулевым аргументом и одно аргументом возвращают реализации, оптимизированные для представления пустых и одиночных списки экземпляров (соответственно).
Если бы у нас не было отдельных перегрузок методов для них и мы включали только один метод на основе varargs, то этот метод мог бы выглядеть примерно так:
public static <E> ImmutableList<E> of(E... es) {
switch (es.length) {
case 0:
return emptyImmutableList();
case 1:
return singletonImmutableList(es[0]);
default:
return defaultImmutableList(es);
}
}
Производительность регистра переключателя (или проверок if-else) не будет плохой для большинства вызовов, но все же в этом нет необходимости, поскольку у него могут быть просто перегрузки методов для каждой оптимизации, и компилятор всегда знает, какую перегрузку вызывать. На код клиента не ложится бремя, так что выиграть легко.