我只是看着Guava的ImmutableList
,我注意到of()
方法超载了12次。
在我看来,他们所需要的只是:
static <E> ImmutableList<E> of();
static <E> ImmutableList<E> of(E element); // not even necessary
static <E> ImmutableList<E> of(E... elements);
有这么多相似变化的原因是什么?
答案 0 :(得分:39)
Varargs和泛型不能很好地融合在一起。 Varargs方法可以使用泛型参数引发警告,并且重载会阻止该警告,除非在极少数情况下您希望使用of()
将超过11个项添加到不可变列表中。
消息来源的评论说:
这些最多可达11个。之后,您只需获得varargs表单,以及可能出现的任何警告。 :(
请注意,Java 7的@SafeVarargs注释是专门添加的,以消除对此类事物的需求。可以使用带有of(E...)
注释的单个@SafeVarargs
方法,并且不会使用泛型参数发出警告。
答案 1 :(得分:13)
还有一个表现原因。每次调用varargs方法都会导致数组分配和初始化。如果你以某种方式确定了95%的调用带有3个或更少的参数,只有5%有4个或更多,然后像这样重载
public static <E> ImmutableList<E> of();
public static <E> ImmutableList<E> of( E e );
public static <E> ImmutableList<E> of( E e1, E e2 );
public static <E> ImmutableList<E> of( E e1, E e2, E e3 );
public static <E> ImmutableList<E> of( E e1, E e2, E e3, E... es );
在95%的案例中带来了良好的性能提升。不同的是,平均案例表现上升。
答案 2 :(得分:4)
除了这里的其他优秀答案之外,还有一个微妙的运行时性能优势(除了避免数组分配),这是零arg和单arg重载返回为表示优化的实现空单实例列表(分别)。
如果我们没有单独的方法重载,并且只包含一个基于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);
}
}
对于大多数调用来说,switch case(或if-else check)的性能不会很糟糕,但它仍然是不必要的,因为每个优化只能有方法重载,并且编译器总是知道哪个超载来调用。客户端代码没有任何负担,因此很容易获胜。