我必须在内存中保留数千个字符串,以便在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在性能方面没有实质性的差异)。