【问题标题】:Why does Guava's ImmutableList have so many overloaded of() methods?为什么 Guava 的 ImmutableList 有这么多重载的 of() 方法?
【发布时间】:2011-04-13 20:46:46
【问题描述】:

我只是在看 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);

为什么会有这么多相似的变体?

【问题讨论】:

  • 无论如何,它们都将参数传递给内部可变参数方法......呵呵。我将不得不在这个问题上扬起眉毛。嗯,消息来源有一条评论“这些最多十一个。在那之后,你只会得到可变参数形式,以及可能出现的任何警告。:(”。不过,我不确定它指的是什么警告。
  • @Tim,这可能会是一个很好的答案,至少值得并投赞成票,并且可能会被接受。
  • +1 为 Google 提供最多 11 点!
  • @romacafe 我认为 Google 被击败了:svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/main/org/… 尽管 Groovy 出于性能原因这样做。最近在 Hack News (news.ycombinator.com/item?id=1951803) 上讨论了它
  • “这些到十一点。” -- en.wikipedia.org/wiki/Up_to_eleven

标签: java guava overloading


【解决方案1】:

可变参数和泛型不能很好地配合使用。 Varargs 方法可能会导致带有泛型参数的警告,并且重载会阻止该警告,除非在极少数情况下您希望使用 of() 将超过 11 个项目添加到不可变列表中。

来源中的cmets说:

这些上升到十一点。之后,您将获得 varargs 表单,以及随之而来的任何警告。 :(

请注意,Java 7 的 @SafeVarargs 注释是专门添加的,以消除对此类事情的需要。可以使用带有 @SafeVarargs 注释的单个 of(E...) 方法,并且不会给出带有泛型参数的警告。

【讨论】:

  • 嘿,您能否更新您的答案以反映@Rinke 引用的性能部分?我认为值得一提。
  • @JoãoRebelo:这实际上不是真的……这些方法只是立即去自己调用一个可变参数方法。
  • 你的意思是在这种特殊情况下吗?还是我误解了你的意思?
  • @JoãoRebelo:我的意思是,对于大多数ImmutableList.of(...) 重载,它们被实现为construct(e1, e2, e3, e4) 等,其中construct 被定义为construct(Object... elements)。所以无论如何都会分配一个数组。 (我想有一些优点,比如知道传递给construct 的数组是调用者无法修改的内部数组,因此在大多数情况下您最终不需要复制该数组,但我不需要不认为这特别值得关注——这肯定不是创建这些方法的主要原因。)
  • 这很有趣。我只是通过源来检查这种好奇心。这是一个很好的信息,并提醒人们不要总是根据假设工作。
【解决方案2】:

还有一个性能原因。每次调用 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% 的情况下会带来不错的性能提升。换句话说,平均案例表现会上升。

【讨论】:

  • 注意:虽然原则成立,但我刚刚从 ColinD 了解到,这实际上不适用于 Guava,因为重载的方法无论如何都会导致 varargs 调用(在当前实现中)。
【解决方案3】:

除了此处的其他出色答案外,还有一个微妙的运行时性能优势(除了避免数组分配),即零参数和单参数重载返回的实现经过优化以表示空和单-instances 列表(分别)。

如果我们没有为这些单独的方法重载并且只包含一个基于 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 检查)的性能对于大多数调用来说都不会差,但它仍然没有必要,因为每次优化都可以有方法重载,并且编译器总是知道要调用哪个重载。客户端代码没有负担,因此很容易获胜。

【讨论】:

    猜你喜欢
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-17
    相关资源
    最近更新 更多