【问题标题】:Declaring initial capaity for a list in java is a bad technique?在 java 中声明列表的初始容量是一种不好的技术?
【发布时间】:2015-09-10 02:46:13
【问题描述】:

我有多个容量相同的 ArrayList。我通过读取文件来填写这些列表。

我知道 Array 和 ArrayList 之间的一个区别是 Array 具有固定容量,而 ArrayList 具有可变容量。您应该在声明时明确指定数组长度,但 ArrayList 会在满时重新调整大小。

ArrayList 中的任何调整大小操作都会降低性能,因为它涉及创建新数组并将内容从旧数组复制到新数组。因此,我想:

A - 使用 first 的容量显式初始化 ArrayList 的其余部分,因此这些列表不必调整自己的大小并将旧的数组元素复制到新的数组中,或者,

B - 我可以放弃其他列表,我只声明第一个列表,其余的将是具有 ArrayList 长度的数组。

例子:

答:

static ArrayList<ObjectType> list1 = new ArrayList<>();
ArrayList<ObjectType> list2 = new ArrayList<>(list1.size());
ArrayList<ObjectType> list2 = new ArrayList<>(list1.size());
...

乙:

static ArrayList<ObjectType> list1 = new ArrayList<>();
ObjectType[] array1 = new  ObjectType[list1.size()]; 
ObjectType[] array2 = new  ObjectType[list1.size()];
ObjectType[] array3 = new  ObjectType[array1.length];
...

问题是:

A 示例是一种糟糕的编程技术吗?但是 B 的例子呢?

用哪个例子比较好?

【问题讨论】:

  • 我完全不明白你的目标是什么。 list1 的内容是什么?
  • 根据您要执行的操作,您可以简单地使用ArrayList&lt;&gt;(list1);,它将获取list1 的副本。向ArrayList 提供任何大小信息的原因是为了在其接近容量时提高性能。没有好坏之分,它们都完成了同样的事情,但ArrayList 是动态的,这意味着它可以增长......
  • 你怎么知道你需要多少额外的列表?如果你知道这个数字,为​​什么不直接用那个容量初始化你的原始列表呢?
  • @Sotirios Delimanolis:我说我正在从文件中读取元素。首先,我在 list1 中添加元素。下一个 listh 的容量将与 list1 的容量相等。因此,我随后在下一个列表中添加的元素在调整大小后不必复制到新调整大小的 ArrayList 中,因为它已完全填充。对于删除评论的人:ArrayList的第一个容量不是0,而是一个正数:link
  • @Sotirios Delimanolis:我知道我需要多少额外的列表,因为我知道我在阅读的文件中寻找什么样的元素。那不是问题....

标签: java arrays list arraylist collections


【解决方案1】:

创建具有初始容量的 ArrayList 一点也不差。事实上,它会为您提供更好的性能,因为在您不断向列表中添加元素时,每次大小已满时,它都不必重新分配内存并复制现有内容。

来自Java docs

每个 ArrayList 实例都有一个容量。容量是大小 用于存储列表中元素的数组。它总是在 至少与列表大小一样大。随着元素被添加到 ArrayList,它的容量会自动增长。成长的细节 除了添加元素具有 固定摊销时间成本。

应用程序可以增加 ArrayList 实例的容量 在使用 ensureCapacity 添加大量元素之前 手术。这可能会减少增量重新分配的数量。

【讨论】:

  • 你认为哪个例子更好?我认为,如果我指定后续列表的初始容量,则在内存分配方面将与 B 示例中的数组完全一样。
  • ArrayList 也是一个仅在幕后实现的数组。当您考虑内存分配时,使用ArrayList 可能会使用比数组高的非常小的常量内存。但是您有很多好处,例如轻松添加和删除元素。所以,我会选择 ArrayList 实现。
  • 确实,我使用列表有很多好处,而且代码更清晰。我将初始化后续列表的容量。谢谢大家的帖子!
【解决方案2】:

我设置列表初始大小的唯一时间是当我确定我知道该列表将包含多少元素时。在下面的示例中,stuffNames 中的元素数量将与原始 stuffList 完全相同。因此,我们防止列表在添加时自行扩展。

好:

    List<Stuff> stuffList = getStuff();
    List<String> stuffNames = new ArrayList<String>( stuffList.size() );
    for (Stuff stuff : stuffList) {
        stuffNames.add( stuff.getName() );
    }

但在本例中,我们并不总是添加名称,具体取决于 hasNiceName() - 因此在本例中,我们创建了一个容量大于可能需要的列表。

不好:

    List<Stuff> stuffList = getStuff();
    List<String> stuffNames = new ArrayList<String>( stuffList.size() );
    for (Stuff stuff : stuffList) {
        if (stuff.hasNiceName()) {
            stuffNames.add( stuff.getName() );
        }
    }

但是,对于我的好例子,这取决于您是否认为这是一种代码异味,以及自扩展列表与开发人员无关。

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 2011-07-01
    • 1970-01-01
    • 2011-02-06
    相关资源
    最近更新 更多