Browsing google's guava collect library code, I've found the following:
// Casting to any type is safe because the list will never hold any elements.
@SuppressWarnings("unchecked")
public static <E> ImmutableList<E> of() {
return (ImmutableList<E>) EmptyImmutableList.INSTANCE;
}
public static <E> ImmutableList<E> of(E element) {
return new SingletonImmutableList<E>(element);
}
public static <E> ImmutableList<E> of(E e1, E e2) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2));
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3));
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3, e4));
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5));
}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6));
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6, e7));
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6, e7, e8));
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
return new RegularImmutableList<E>(
ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6, e7, e8, e9));
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList(
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10));
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) {
return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList(
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11));
}
public static <E> ImmutableList<E> of(
E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11,
E e12, E... others) {
final int paramCount = 12;
Object[] array = new Object[paramCount + others.length];
arrayCopy(array, 0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12);
arrayCopy(array, paramCount, others);
return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList(array));
}
And although it seems reasonable to have overloads for empty and single arguments (as they are going to use special instances), I cannot see the reason behind having all the others, when just the last one (with two fixed arguments plus the variable argument instead the dozen) seems to be enough.
As I'm writing, one explanation that pops into my head is that the API pre-dates Java 1.5; and although the signatures would be source-level compatible, the binary interface would differ. Isn't it?