Java 中 Array 和 ArrayList 的比较和转换

original - Java Array vs. ArrayList: Comparison and Conversion author - Lokesh Gupta

Java 编程中,arraysarraylists 都是基本的数据结构,用来存放数据集合。虽然两者的用途一样,但是它们的特点极大地影响应用的性能和灵活性。

本文探讨 arraysarraylists 的重要特性,它们各自的强项和弱点。当需要的时候,实现两种数据结构的无缝转换。

1. 介绍

Java 中,ArrayList 是集合框架的一部分,是可调整数据结构的实现。这一位意味着 arraylist 内部维护了一个需要动态增长或者收缩的数组。

1.1 Java Arrays

array 是一个固定大小的数据结构,在连续的内存空间中存放相同类型的数据。 array 中的每个元素通过索引或者位置识别,首个元素从 0 开始。

Java 语言中的 arrays 跟其他语言中的数组类似。通常,它们有下面的特性:

  • Arrays 通常存储同种数据类型的元素。数据的类型在初始化的时候就已经定义好。
  • 一个整数类型数组只能存放整数。Java 的编译器不允许在整数类型的数组中存放字符串数据。
  • 数组中的每个元素只能通过索引获取。没有其他获取数组元素的方法。
  • 数组的大小通常是固定的并且不能更改。要存放比数组大小更多的元素,我们必须创建新的数组,然后将旧数组数据拷贝到新数组。当我们尝试添加超过数组大小的元素,将会抛出 ** ArrayIndexOutOfBoundsException** 错误。

比如,以下数组是其在内部存储器的表现:

java 复制代码
int [] a = new int[5];

a[0] = 1;
a[1] = 2;
a[2] = 4;
a[3] = 8;
a[4] = 16;

Arrays 有一个固定的长度,这就是说一旦数组被创建,数组大小不可以被改变。数组中元素的获取通过响应的索引获取。

java 复制代码
for(int i = 0; i < a.length; i++) {
  System.out.println(a[i]);
}

1.2 Java ArrayList

ArrayList 类是 Java 集合框架的一部分,用来实现 List 接口。不像 arraysArrayLists 伴随着元素的添加或者移除来增长或者缩小。

可以在 arraylist 中存放多种类型的元素,但是通常不推荐,因为在运行时获取数组元素时可能会引发 ClassCastException 异常。为了确保类型安全,泛型 generics 被用来声明存储在 arraylist 中的元素类型。

java 复制代码
List<Integer> arraylist = new ArrayList<>();

arraylist.add(1); // allowed

// arraylist.add("one"); // NOT allowed

除了可以使用 for 循环来顺序获取之外,arraylist 也允许使用迭代器来获取,比如 ListIterator。当我们使用迭代器并使用迭代器修改集合时,不会抛出 ConcurrentModificationException 异常。

java 复制代码
List<Integer> arraylist = new ArrayList<>();

arraylist.add(1);
arraylist.add(2);
arraylist.add(3);

// 1 - using foreach loop
arraylist.forEach(System.out::println)

// 2 - using iterator
ListIterator<Integer> listIterator = arraylist.listIterator();
while(listIterator.hasNext()) {
  System.out.println(listiterator.next());
}

2. Java 中 Array 和 ArrayList 的不同

下面的表格是 arraysarraylists 的比较总结。比较这两个数据机构,基于它们的性能,使用和场景。

特性 Arrays ArrayLists
固定大小和动态大小 在初始化的时候就分配固定大小 动态调整大小,随着元素的添加或删除而变化
内存管理和效率 如果数组大小超出了实际需要的个数,固定大小可能导致内存浪费 动态调整大小会带来轻微的性能开销,但是可以优化内存使用
语法和使用难易 初始化,增加,移除和更新操作语法很直白 使用 Collections API 方法更直观、更方便工作
性能 对于读/写操作,arrays 通常很快,因为它是直接使用元素索引获取。对于需要调整大小的写操作,arraylists 性能优于 array 除了需要调整大小的写操作,其他的操作 arraylists 表现得比 arrays
类型安全 Arrays 具有有限的类型安全性,并允许任何类型的元素存储在同个数组中 通过泛型,ArrayLists 提供更好的类型安全性,确保特定类型的元素被存储
最佳使用场景 当需要固定大小的集合并且看中内存效率,则使用 array ArrayList 最适合用于小型的集合,其中方便性微小且可忽略的性能提升

3. Array 转换为 ArrayList

Array 转换为 ArrayList 最直接的方法是使用 Arrays.asList() 方法,该方法创建了数组的列表视图,然后我们使用 ArrayList 构造函数创建一个新的 ArrayList。这有效地将数组转换为 ArrayList

java 复制代码
String[] array = {"apple", "banana", "cherry"};

ArrayList<String> arrayList = new ArrayList<>(Arrays.asList(array));

另外,我们也可以使用 Java 8 streams 来迭代数组元素,并将它们收集在一个新的 ArrayList 中。它给我们提供了在将元素收集到列表前对数组的每个元素执行额外操作的机会。

java 复制代码
ArrayList<String> arrayList = Arrays.stream(array)
    // additional actions
    .collect(Collectors.toCollection(ArrayList::new));

4. ArrayList 转换为 Array

最简单的转换一个 arraylistarray 方案是使用 ArrayList.toArray() 方法,该方法返回一个包含列表中所有元素的数组,并且元素顺序正确。toArray() 返回 Object[] 类型的数组,所以你需要提供你想要的数组类型作为参数。

新数组的大小是由 ArrayList 大小决定的。

java 复制代码
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("apple");
arrayList.add("banana");
arrayList.add("cherry");

String[] array = arrayList.toArray(new String[arrayList.size()]);

5. 最佳实践和推荐

ArrayListsarrays 都有相同的目的和各自的优点。以下建议是有助于我们缩小范围并选择适合我们应用程序的正确数据结构。

5.1 频繁更改大小操作

因为特殊的需求,如果数组需要频繁更改大小,建议使用 ArrayList 调整大小操作的内部处理消除了应用程序代码的复杂度,并提供了和手动修改相似的性能增益。

5.2 性能提升的可量化

如果性能提升不是很重要,那么还是推荐使用 arraylists ArrayLists 避免了复杂性,并且让代码可读性更高,且性能在处理小的集合跟 array 相似。

衡量性能增益的最佳方式是使用诸如 JMH 之类的工具进行测量。

5.3 原始类型 VS 包装对象

Array 可以直接处理原始类型,而 arraylists 则与对象(即包装类)一起使用。 如果在应用程序中处理它们时需要不断进行两种类型的转换,最好使用 arrays,因为它们会消除不必要的类型转换来简化代码,并因此带来轻微的性能提升。

java 复制代码
int[] array = new int[10];

//Creating arraylist for 'int' type is not possible. We must create arraylist of type 'Integer'

ArrayList<Integer> arraylist = new ArrayList<>();

5.4 与其他集合类型互操

ArrayListJava 集合框架的一部分,所以和其他类型(比如:MapSet)的操作是无缝的。使用 arrays 将会产生转换成其他类型不必要的额外步骤。

使用 arraylist 将减少这类的转换,因此代码可读性更高且更简洁。

6. 总结

总之,Java 开发的最佳实践通常推荐使用 ArrayLists 和其他内置的集合类,因为它们更灵活,并且相比中等大小的集合性能相似。

然而,arrays 也有实用的场景,特别是在意性能和内存效率的情况。

相关推荐
颜进强3 分钟前
Embedding 模型介绍:热门模型对比与应用场景
前端·后端·ai编程
颜进强4 分钟前
LanceDB 基础使用:用 TypeScript 完成第一次向量检索
前端·后端·ai编程
xyphf_和派孔明5 分钟前
企业级微前端项目完整创建步骤,第二步:配置主应用
前端
武子康6 分钟前
低延迟不是更快地猜:EOU / Barge-in / Turn Protocol 必须统一(4 种结束 + Generation Fencing + 9 类可复现场景)
人工智能·后端·llm
默_笙11 分钟前
🔑 让 AI 学会"读"网页:我用 Cheerio 爬了一篇掘金文章,然后切成小块存进了向量库
前端·javascript
颜进强11 分钟前
Ollama 从入门到实践:本地模型运行、API 调用
前端·后端·ai编程
今天AI了吗15 分钟前
Spring AI 框架实战:Java 后端集成大模型的架构设计与工程落地
java·人工智能·python·spring·机器学习
颜进强16 分钟前
Embedding 基础使用:用 Ollama 和 LangChain.js 生成文本向量
前端·后端·ai编程
颜进强20 分钟前
Vector Store 入门:什么是向量数据库,主流产品如何选择
前端·后端·ai编程
hexu_blog26 分钟前
springboot3集成shardingsphere4.0 分表分库
java·spring boot·mybatis