【问题标题】:Advantages of creating an ArrayList with initial capacity of 0?创建初始容量为 0 的 ArrayList 的优点?
【发布时间】:2015-04-05 09:36:00
【问题描述】:

我是一位经验丰富的 Java 开发人员,我经常看到这样的事情

List<Integer> l = new ArrayList<Integer>(0);

我真的无法理解。当您知道它的增长将超出容量时,创建初始容量为 0 的 ArrayList 有什么意义?

这样做有什么已知的好处吗?

【问题讨论】:

标签: java arraylist capacity


【解决方案1】:

根据合同,您可以通过不包含空值来避免 NullPointerExceptions。在某些情况下这是一种很好的做法,请参阅 Joshua Bloch 的 Effective Java Item 43: Return empty arrays or collections, not nulls

【讨论】:

  • 显然,问题不是对比 ArrayList() 与 ArrayList(),而是询问使用 ArrayList(0) 的一般原因。当然,还有其他选择。
【解决方案2】:

为数组列表提供较大的值(如果您将超过多少列表)总是更好的方法,因为它会减少列表的大小调整,从而优化您的执行时间。

使用值 0 初始化数组列表创建 Empty 数组列表 reducing memory 如果您知道您的列表不会比 10 内容更多。

【讨论】:

  • 是的,这是正确的,而不是将null 值保留在数组列表中,而是将其初始化为零。
  • @vikingsteve 感谢您的回复,我编辑了我的答案。
  • 好的,我删除了我的反对票。您的答案现在好多了,感谢您抽出时间再次编辑它。
  • @vikingsteve 我喜欢你帮助我改进我的答案。
【解决方案3】:

对于 java 6(或 openjdk 7),不指定初始大小会给您一个初始大小设置为 10 内的列表。因此,根据您使用列表的许多因素,使用大小0 初始化列表可能会稍微提高内存和/或性能效率。

对于 java 7,指定初始大小 0 在功能上等同于不指定初始大小。

但实际上效率较低,因为使用参数0 调用构造函数会导致调用new Object[0],而如果指定无参数构造函数,则列表的初始elementData 设置为一个名为EMPTY_ELEMENTDATA 的静态定义常量。

相关代码来自ArrayList 来源:

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

换句话说,使用new ArrayList&lt;Integer&gt;(0); 似乎是多余的,这样做没有任何好处,我会改用new ArrayList&lt;Integer&gt;();

【讨论】:

【解决方案4】:
  • 如果对 ArrayList 的添加确实不太可能,并且如果将 ArrayList 的大小保持在最低限度很重要,那么我认为这很有用。

  • 或者,如果 ArrayList 的唯一目的是作为方法的返回值,其中返回空列表是给函数调用者的特殊消息,例如“未找到结果”。

  • 否则,不是真的。

【讨论】:

    【解决方案5】:

    它使ArrayList 的大小(在内存中)非常小,当您希望变量不为空并准备好使用时,这是一种策略,但不要期望 立即填充List。如果您希望它立即被填充,最好给它一个更大的初始值 - ArrayList 的任何“增长”都在内部创建一个新的原始数组,并复制项目。 ArrayList 的增长代价高昂,应尽量减少。

    或者,如果您要创建 很多 个类的实例,每个实例都包含这些 List 属性之一。如果您不立即计划填充它们,则可以通过暂时不分配房间来节省一些内存。

    但是:有更好的方法:Collections.emptyList()。通常,您会希望直接保护对该列表的访问,并且(例如)在您的类中提供对内部List 进行操作的特定于域的方法调用。例如,假设您有一个包含List 学生姓名的School 类。 (为了简单起见,请注意这个类不是线程安全的。

    public class School {
        private List<String> studentNames = Collections.emptyList();
    
        public void addStudentName(String name) {
            if (studentNames.isEmpty()) {
                studentNames = new ArrayList<String>();
            }
            studentNames.add(name);
        }
    
        public void removeStudentName(String name) {
            studentNames.remove(name);
            if (studentNames.isEmpty()) {
                studentNames = Collections.emptyList(); // GC will deallocate the old List
            }
        }
    }
    

    如果您愿意进行isEmpty() 检查并执行初始化/分配,这是创建大量空ArrayList 实例的更好选择,因为Collections.emptyList() 是一个静态实例(仅存在一个)并且不可修改。

    【讨论】:

      【解决方案6】:

      默认ArrayList 的容量为10,每次调整大小为+50%。

      通过使用较低的初始容量,您可以有时(理论上)节省内存。另一方面,每次调整大小都很耗时。在大多数情况下,这只是抢先优化的标志。

      【讨论】:

      • 这也是我的想法,但刚刚检查了 openjdk 7 的源代码,它现在通过使用@vikingsteve 描述的共享空元素进行优化。
      猜你喜欢
      • 1970-01-01
      • 2023-01-25
      • 1970-01-01
      • 2016-07-13
      • 2012-08-08
      • 2013-03-04
      相关资源
      最近更新 更多