首页 >Java >java教程 >[代码比较] ArrayList vs Collections.singletonList

[代码比较] ArrayList vs Collections.singletonList

WBOY
WBOY原创
2024-08-06 13:20:50421浏览

[Code Compare] ArrayList vs Collections.singletonList

我正在启动一个新线程来比较编码相同功能的不同方法。在这篇文章中,我将比较两种创建仅包含一个元素的简单列表的常用方法。具体来说,我将研究最常用的 List 实现构造函数和 Collections.singletonList,这是一个简单的工厂方法,用于创建包含单个元素的不可变列表。

数组列表

每次初始化 ArrayList 而不指定其初始容量时,它都会以空数组开始。添加第一个元素时,ArrayList 使用涉及复制数组的相对复杂的算法来调整大小。我们来看看ArrayList的结构:

  private static final int DEFAULT_CAPACITY = 10;
  private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

  public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  }

  public boolean add(E e) {
    modCount++;
    add(e, elementData, size);
    return true;
  }

  private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
  }

  private Object[] grow() {
      return grow(size + 1);
  }

  private Object[] grow(int minCapacity) {
    return elementData = Arrays.copyOf(elementData,
                                      newCapacity(minCapacity));
  }

  private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity <= 0) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    }
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);
  }

以下是逐步发生的事情:

  1. 创建了一个初始空数组 elementData。
  2. 添加第一个元素时,会将当前大小(为零)与数组的长度进行比较。
  3. 由于发现其大小为零,因此数组需要增长以容纳新元素。
  4. 调用grow方法,计算新的容量。
  5. 新容量最初增加了旧容量的一半,这让我们有 0 + 0/2 = 0。
  6. 由于newCapacity不足以容纳该元素,因此继续。
  7. 由于发现 elementData 是相同的初始空数组,因此它最终返回所需大小 (1) 和 DEFAULT_CAPACTIY (10) 之间的最大值,从而得到大小为 10 的数组。

当您只需要一个始终包含单个元素的简单列表时,调整大小的过程非常复杂。

也就是说,让我们谈谈我们的替代方案!

集合::singletonList

方法签名:

公共静态;列表 singletonList(T o)

描述

此方法返回一个仅包含指定对象的不可变列表。 Java 1.3中引入的singletonList有几个优点:

  1. 内联实现:您可以在一行中使用所需的元素对其进行初始化。
  2. 不变性:让我们看一下它的实现:

    private static class SingletonList<E> extends AbstractList<E>
        implements RandomAccess, Serializable {
    
      private final E element;
    
      SingletonList(E obj) {
        element = obj;
      }
      ...
    }
    

    SingletonList 继承自的 AbstractList 定义了所有可变方法,如下所示:

      public boolean add(E e) {
        add(size(), e);
        return true;
      }
    
      public void add(int index, E element) {
        throw new UnsupportedOperationException();
      }
    
      public E remove(int index) {
        throw new UnsupportedOperationException();
      }
    
      public E set(int index, E element) {
          throw new UnsupportedOperationException();
      }
    

    这确保了不可能重复列表的大小或其单个元素的内容。

    不变性是一个非常有利的特性。虽然我不会在这里深入探讨,但感兴趣的开发者可以从本文中了解更多信息。

  3. 内存分配: SingletonList 类仅包含一个简单字段来容纳单个元素,与 ArrayList 不同,ArrayList 使用数组,使用简单的 ArrayList 简单构造函数,将为我们留下一个数组添加元素后大小为 10。

  4. CPU 使用率: SingletonList 构造函数接受单个元素作为参数,不需要调整大小、数组复制或操作。与 ArrayList 添加方法相比,这效率要高得多。

结论

在这篇文章中,我们比较了使用单个元素创建简单列表的两种方法:使用 ArrayList 构造函数和 Collection.singletonList 方法。虽然 ArrayList 是一种灵活且常用的数据结构,但它会带来一些不必要的开销,特别是在添加元素时的内存分配和 CPU 使用方面。这一开销包括调整数组大小和复制数组,这对于仅包含一个元素的列表来说可能是多余的。但是,如果您需要更改此元素,ArrayList 是一个合适的解决方案。

另一方面,Collection.singletonList 为创建单元素列表提供了更有效的替代方案。这种方法不仅更简洁、更易于使用,而且保证了不变性,这在很多场景下都是一个显着的优势。与 ArrayList 相比,它具有最小的内存占用,并且几乎不需要 CPU 资源。

总而言之,对于仅包含一个元素的简单、不可变列表,Collection.singletonList 因其高效、简单和不变性而成为更好的选择。但是,如果您需要修改列表中的元素,ArrayList 可能是更合适的选择。

在下一篇文章中,我将比较单元素列表的另一种替代方法:List.of 工厂方法。稍后见!

以上是[代码比较] ArrayList vs Collections.singletonList的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn