我必须在内存中保留数千个字符串,以便在Java中串行访问。我应该把它们存储在数组中还是应该使用某种列表?
由于数组将所有数据保存在一个连续的内存块中(与list不同),使用数组存储数千个字符串会导致问题吗?
我必须在内存中保留数千个字符串,以便在Java中串行访问。我应该把它们存储在数组中还是应该使用某种列表?
由于数组将所有数据保存在一个连续的内存块中(与list不同),使用数组存储数千个字符串会导致问题吗?
当前回答
既然这里已经有了很多好的答案,我想给你一些其他的实际观点的信息,这是插入和迭代性能的比较:Java中的基元数组与链表。
这是实际的简单性能检查。因此,结果将取决于机器的性能。
用于此的源代码如下:
import java.util.Iterator;
import java.util.LinkedList;
public class Array_vs_LinkedList {
private final static int MAX_SIZE = 40000000;
public static void main(String[] args) {
LinkedList lList = new LinkedList();
/* insertion performance check */
long startTime = System.currentTimeMillis();
for (int i=0; i<MAX_SIZE; i++) {
lList.add(i);
}
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("[Insert]LinkedList insert operation with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");
int[] arr = new int[MAX_SIZE];
startTime = System.currentTimeMillis();
for(int i=0; i<MAX_SIZE; i++){
arr[i] = i;
}
stopTime = System.currentTimeMillis();
elapsedTime = stopTime - startTime;
System.out.println("[Insert]Array Insert operation with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");
/* iteration performance check */
startTime = System.currentTimeMillis();
Iterator itr = lList.iterator();
while(itr.hasNext()) {
itr.next();
// System.out.println("Linked list running : " + itr.next());
}
stopTime = System.currentTimeMillis();
elapsedTime = stopTime - startTime;
System.out.println("[Loop]LinkedList iteration with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");
startTime = System.currentTimeMillis();
int t = 0;
for (int i=0; i < MAX_SIZE; i++) {
t = arr[i];
// System.out.println("array running : " + i);
}
stopTime = System.currentTimeMillis();
elapsedTime = stopTime - startTime;
System.out.println("[Loop]Array iteration with " + MAX_SIZE + " number of integer elapsed time is " + elapsedTime + " millisecond.");
}
}
表现结果如下:
其他回答
这取决于你如何访问它。
存储后,如果你主要想做搜索操作,很少或不需要插入/删除,那么就去数组(因为在数组中搜索是在O(1)中完成的,而添加/删除可能需要重新排序元素)。
存储之后,如果你的主要目的是添加/删除字符串,很少或没有搜索操作,那么就去List。
我同意在大多数情况下,您应该选择数组列表的灵活性和优雅性,而不是数组——在大多数情况下,它对程序性能的影响可以忽略不计。
然而,如果你对软件图形渲染或自定义虚拟机进行很少结构变化(没有添加和删除)的频繁迭代,我的顺序访问基准测试表明,数组列表比我的系统上的数组慢1.5倍(在我一岁的iMac上是Java 1.6)。
一些代码:
import java.util.*;
public class ArrayVsArrayList {
static public void main( String[] args ) {
String[] array = new String[300];
ArrayList<String> list = new ArrayList<String>(300);
for (int i=0; i<300; ++i) {
if (Math.random() > 0.5) {
array[i] = "abc";
} else {
array[i] = "xyz";
}
list.add( array[i] );
}
int iterations = 100000000;
long start_ms;
int sum;
start_ms = System.currentTimeMillis();
sum = 0;
for (int i=0; i<iterations; ++i) {
for (int j=0; j<300; ++j) sum += array[j].length();
}
System.out.println( (System.currentTimeMillis() - start_ms) + " ms (array)" );
// Prints ~13,500 ms on my system
start_ms = System.currentTimeMillis();
sum = 0;
for (int i=0; i<iterations; ++i) {
for (int j=0; j<300; ++j) sum += list.get(j).length();
}
System.out.println( (System.currentTimeMillis() - start_ms) + " ms (ArrayList)" );
// Prints ~20,800 ms on my system - about 1.5x slower than direct array access
}
}
在存储字符串对象的情况下,数组还是列表的选择并不那么重要(考虑到性能)。因为数组和列表存储的都是字符串对象引用,而不是实际对象。
如果字符串的数量几乎是常数,则使用数组(或ArrayList)。但如果数字变化太大,那么你最好使用LinkedList。 如果有(或将会)需要在中间添加或删除元素,那么你当然必须使用LinkedList。
首先,有必要澄清一下,您是指经典的compp sci数据结构意义上的“列表”(即链表),还是指java.util.List?如果你指的是java.util。List,它是一个接口。如果你想使用数组,只要使用数组列表实现,你就会得到类似数组的行为和语义。问题解决了。
如果你指的是数组和链表,这是一个稍微不同的参数,我们回到大O(如果这是一个不熟悉的术语,这里有一个简单的英语解释。
数组;
随机存取:O(1); 插入:O (n); 删除:O (n)。
链表:
随机存取:O(n); 插入:O (1); 删除:O(1)。
你可以选择最适合调整数组大小的方法。如果你调整大小,插入和删除很多,那么链表可能是一个更好的选择。如果随机访问很少,情况也是如此。你提到了串行访问。如果你主要做串行访问,很少修改,那么你选择哪一个可能都不重要。
链表的开销略高,因为正如您所说,您正在处理潜在的不连续内存块和(有效地)指向下一个元素的指针。但是,除非您要处理数百万个条目,否则这可能不是一个重要因素。
虽然建议使用数组列表的答案在大多数情况下是有意义的,但相对性能的实际问题还没有真正得到答案。
你可以用数组做以下几件事:
创建它 设置一个项目 买一件物品 克隆/复制它
一般的结论
虽然get和set操作在数组列表(resp。在我的机器上每次调用1和3纳秒),对于任何非密集的用途,使用ArrayList相对于数组的开销非常小。然而,有几件事要记住:
在列表上调整大小操作(当调用list.add(…)时)代价很高,应该尽可能将初始容量设置为适当的级别(注意,在使用数组时也会出现同样的问题) 在处理原语时,数组可以明显更快,因为它们可以避免许多装箱/拆箱转换 一个只在数组列表中获取/设置值的应用程序(不是很常见!)通过切换到数组可以看到超过25%的性能增益
详细的结果
下面是我在标准x86桌面机器上使用JDK 7使用jmh基准测试库(以纳秒为单位)测量这三个操作的结果。请注意,ArrayList在测试中从不调整大小,以确保结果具有可比性。这里有基准代码。
数组/ ArrayList创造
我运行了4个测试,执行以下语句:
createArray1: Integer[] array = new Integer[1]; createList1: List<Integer> List = new ArrayList<> (1); createArray10000: Integer[] array = new Integer[10000]; createList10000: List<Integer> List = new ArrayList<> (10000);
结果(以纳秒为单位,95%置信度):
a.p.g.a.ArrayVsList.CreateArray1 [10.933, 11.097]
a.p.g.a.ArrayVsList.CreateList1 [10.799, 11.046]
a.p.g.a.ArrayVsList.CreateArray10000 [394.899, 404.034]
a.p.g.a.ArrayVsList.CreateList10000 [396.706, 401.266]
结论:无明显差异。
get操作
我运行了2个测试,执行以下语句:
返回list.get(0); 返回数组[0];
结果(以纳秒为单位,95%置信度):
a.p.g.a.ArrayVsList.getArray [2.958, 2.984]
a.p.g.a.ArrayVsList.getList [3.841, 3.874]
结论:从数组中获取信息比从ArrayList中获取信息快25%,尽管差异仅在1纳秒的量级上。
集合操作
我运行了2个测试,执行以下语句:
setList:列表。设置(0,价值); setArray:数组[0]=值;
结果(以纳秒为单位):
a.p.g.a.ArrayVsList.setArray [4.201, 4.236]
a.p.g.a.ArrayVsList.setList [6.783, 6.877]
结论:在数组上的set操作比在列表上快40%左右,但是,对于get,每个set操作需要几纳秒——所以为了达到1秒的差异,需要在列表/数组中设置项数亿次!
无性系/ copy
ArrayList的复制构造函数委托给数组。因此,性能与数组复制相同(通过克隆复制数组,数组。copyOf或System。arrayCopy在性能方面没有实质性的差异)。