我必须在内存中保留数千个字符串,以便在Java中串行访问。我应该把它们存储在数组中还是应该使用某种列表?
由于数组将所有数据保存在一个连续的内存块中(与list不同),使用数组存储数千个字符串会导致问题吗?
我必须在内存中保留数千个字符串,以便在Java中串行访问。我应该把它们存储在数组中还是应该使用某种列表?
由于数组将所有数据保存在一个连续的内存块中(与list不同),使用数组存储数千个字符串会导致问题吗?
当前回答
使用哪一种取决于问题本身。我们得看看大O。
图片来源:https://github.com/egonSchiele/grokking_algorithms
其他回答
更新:
正如Mark所指出的那样,在JVM预热之后(几次测试通过)没有明显的差异。检查与重新创建的数组,甚至新传递开始的新行矩阵。有很大的可能性,这表明简单数组的索引访问不用于有利于集合。
前1-2次简单数组还是快2-3倍。
原来的帖子:
对这个主题来说,太多的词太简单了。毫无疑问,数组比任何类容器都快几倍。我在这个问题上为我的性能关键部分寻找替代方案。下面是我为检查实际情况而构建的原型代码:
import java.util.List;
import java.util.Arrays;
public class IterationTest {
private static final long MAX_ITERATIONS = 1000000000;
public static void main(String [] args) {
Integer [] array = {1, 5, 3, 5};
List<Integer> list = Arrays.asList(array);
long start = System.currentTimeMillis();
int test_sum = 0;
for (int i = 0; i < MAX_ITERATIONS; ++i) {
// for (int e : array) {
for (int e : list) {
test_sum += e;
}
}
long stop = System.currentTimeMillis();
long ms = (stop - start);
System.out.println("Time: " + ms);
}
}
这就是答案:
基于数组(第16行是活动的):
Time: 7064
根据列表(第17行是活动的):
Time: 20950
还有关于“更快”的评论吗?这是可以理解的。问题是什么时候大约3倍的速度比List的灵活性更好。但这是另一个问题。 顺便说一下,我也根据手工构造的数组列表检查了这个。几乎是一样的结果。
如果提前知道数据有多大,那么使用数组会更快。
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
}
}
虽然建议使用数组列表的答案在大多数情况下是有意义的,但相对性能的实际问题还没有真正得到答案。
你可以用数组做以下几件事:
创建它 设置一个项目 买一件物品 克隆/复制它
一般的结论
虽然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在性能方面没有实质性的差异)。
我建议您使用分析器来测试哪个更快。
我个人的观点是你应该使用列表。
我在一个大型代码库中工作,之前的一组开发人员在任何地方都使用数组。这使得代码非常不灵活。在将大块数据转换为列表后,我们发现速度没有变化。