6

我今天了解到,您可以使用如下静态方法创建一个新的 ArrayList 对象:

List<String> listDummy = Arrays.asList("Coding", "is", "fun"); 
ArrayList<String> stringList = new ArrayList<>(listDummy);

或者更简洁:

ArrayList<String> stringList = new ArrayList<>(Arrays.asList("Coding", "is", "fun"));

我的问题是:与“传统”方式相比,这种性能成本有多高?(以下)

ArrayList<String> stringList = new ArrayList<>();
stringList.add("Coding");
stringList.add("is");
stringList.add("fun");

我意识到创建 ArrayList 的上层方法包括一个额外的 List 对象创建,但是,我更喜欢更短更紧凑的语法,以至于我愿意牺牲一些性能但必须在某个地方划清界限。

PS。在“new ArrayList<>()”中将类型信息(<>) 留空是 Java SE 7 的一项功能,而不是错误。

预先感谢您的任何回答!

4

7 回答 7

5

性能差异可能为 30 - 300 ns,具体取决于您的系统和代码的预热程度。我怀疑性能差异很小。

如果有疑问,我总是说;尽可能简单和清晰地编写代码,并且它通常也可以正常运行。

于 2013-06-11T10:16:36.413 回答
2

通常的add()方式调用三个方法。

asList()方法创建一个数组,然后clone()对其执行(执行浅拷贝),然后由于此错误而手动复制所有元素。之后,如果您想向 中添加另一个元素stringList,则必须使数组更大并重新复制元素,因为大小对于提供的元素是精确的。(所有这些都依赖于实现并假设 Oracle JDK)

对于三个元素,后者会慢一些,但对于任何实际使用来说,都可以忽略不计。对于许多元素,这两种方法的性能可能相同,而前一种甚至可能会变慢。

写你认为读得最好的,性能损失是最小的,你不应该关心它,直到它证明自己是瓶颈。


综上所述,如果您追求简洁的语法,您可能会喜欢 Google Guava 的Lists

List<String> stringList = Lists.newArrayList("Coding", "is", "fun");

我已经有一段时间没有使用经典的ArrayList构造函数了。

于 2013-06-11T10:26:06.930 回答
1

您可以在一行中完成,而无需创建其他列表:

ArrayList<String> stringList = new ArrayList<>(){{
    add("Coding");
    add("is");
    add("fun");
}};

这是一个匿名类,它是ArrayList 的子类,带有一个实例块。

于 2013-06-11T10:17:55.370 回答
1

如果您不打算在创建后从列表中添加/删除元素,那么最好的方法是根本不创建 ArrayList,这将非常有效

List<String> listDummy = Arrays.asList("Coding", "is", "fun"); 

否则new ArrayList<>(listDummy)比手动逐个添加元素更有效,请参阅 ArrayList(Collection) src:

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

它已优化:

1) 它创建精确大小的数组
2) 它使用元素的本机复制

于 2013-06-11T10:19:33.610 回答
1

你从 Arrays.asList 得到的列表已经是一个 ArrayList,所以没有必要再次用 ArrayList 包装它:

  public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
    }

警告:该列表是只读的,因此如果您需要编写它,您将需要使用 new ArrayList(..) 来包装它。

不过,我认为使用 Arrays.asList 应该比使用重复调用“add”来创建列表更好,因为 ArrayList 的内部数组是用正确的大小初始化的。所以最好的方法是

List<String> myList= Arrays.asList("Coding", "is", "fun");
// or if you need to write the list
List<String> myList = new ArrayList(Arrays.asList("Coding", "is", "fun"));

这也是最易读的恕我直言,对我来说,可读性总是胜过非常小的性能提升,除非你真的需要额外的性能。如果您确实需要进行性能调整,请使用分析器。瓶颈通常是您不希望出现的地方。分析器可以为您提供有关程序哪些部分运行缓慢的确切信息,您可以根据需要对其进行优化。

于 2013-06-11T10:19:53.520 回答
0

性能差异取决于源阵列的大小。

如果您要在目标数组中一一添加项目,则会发生多个重新分配。

如果您一次添加整个集合,则只需进行一次分配,因为大小是事先知道的。

于 2013-06-11T10:21:25.517 回答
0

我有时会使用便利功能:

public static <T> ArrayList<T> asArrayList(T... args) {
    ArrayList<T> list = new ArrayList<T>(args.length);
    Collections.addAll(list, args);
    return list;
}

这比Arrays.asList路线快一点。(并不是说硬编码列表真的很重要。)

于 2013-06-11T11:23:14.550 回答