将ArrayList <string []>高效转换为JAVA </string []>中的多行字符串

时间:2014-09-09 05:42:23

标签: java arrays string performance

ArrayList<String[]> writtenClasses = new ArrayList<String[]>();
// usually there is functional code here that populates
// ArrayList<String[]> writtenClasses with variably 3000
// String[] objects always of exactly 8 lines each

ArrayList<String> processedClasses = new ArrayList<String>();
for(String[] classLines: writtenClasses)
{
    for(String classLine: classLines)
    {
        processedClasses.add(classLine);
    }
}

String result = "";
for(String fileLine: processedClasses)
{
    result += fileLine + "\n";
}

我的代码在上面。它工作正常,产生我想要的结果,只是缓慢。每个项目的ArrayList书写类需要大约10毫秒,这是好的,直到我给它更大的工作。我怀疑与ArrayLists有关的事情已经花了这么长时间,但是在每次运行后,计时器和打印到控制台工作统计数据都显得很少。

上面的代码是对早期代码的改编,希望能提高效率。它的成功率约为4%。下面的代码是我使用的旧方法,它只需要比上面更长的时间。

for(String[] classLines: writtenClasses)
{
    for(String classLine: classLines)
    {
        result += classLine + "\n";
    }
    writtenClasses.set(writtenClasses.indexOf(classLines), null);
}

我只是为了提高内存效率而writtenClasses.set(writtenClasses.indexOf(classLines), null);,而我的统计数据显示,它在不可检测的CPU工作量下更有效地使用内存。

这是我在StackOverflow上的第二个问题,我已尽力遵守规则,但如果我对此表示严重或在某种程度上无意中不注意,请向我强调我会解决这个问题。 :)

5 个答案:

答案 0 :(得分:3)

创建中间processedClasses列表绝对没用。此外,StringBuilder将显着加快流程:

// Consider a large initial size to even avoid reallocation, here I used 64 KB
StringBuilder sb = new StringBuilder(65536);

for (String[] classLines : writtenClasses)
    for (String lines : classLines)
        sb.append(lines).append('\n');

// Note: you might not even need to convert it to String, read reasoning below
String result = sb.toString();

我们在StringBuilder中构建内容,该StringBuilder实现CharSequence接口。许多课程都接受CharSequence而不只是String。一个很好的例子是FileWriter。在这些情况下,您甚至无需将StringBuilder转换为String,因为StringBuilder可以像String结果一样轻松传递,这可能是另一种表现如果内容非常大,则有优势。

答案 1 :(得分:2)

其他答案已经指出了这个问题。使用Java 8,两个嵌套循环和StringBuilder的替代方法是使用流和连接收集器*:

String result = writtenClasses.stream()
        .flatMap(array -> Arrays.stream(array))
        .collect(joining("\n"));

*需要import static java.util.Collectors.joining;

答案 2 :(得分:1)

不是一个正确的答案,但在评论中读得太尴尬了:

String result = "";
for(String fileLine: processedClasses)
{
    result += fileLine + "\n";
}

这就是创建了一百万个String实例。我想在这里使用StringBuilder会对性能产生积极影响。

答案 3 :(得分:1)

这里的主要痛点可能不是ArrayList,而是+运算符与String的使用。由于String在java中是不可变的,因此每次调用都会强制创建一个新对象并复制所有数据,正如您所说,这些数据可能会很长。

更快的方法是使用StringBuilder,它不会(必然)强制复制每个操作的数据:

StringBuilder result = new StringBuilder();
for(String[] classLines: writtenClasses)
{
    for(String classLine: classLines)
    {
        result.append(classLine).append('\n');
    }
}

答案 4 :(得分:0)

基于此question

ewall:

At what point do you switch to StringBuilder? When it effects memory or performance. Or when it might. If you're really only doing this for a couple strings once, no worries. But if you're going to be doing it over and over again, you should see a measurable difference when using StringBuilder.

StringBuilder myString = new StringBuilder();

     for(String classLine: classLines)
        {
           myString.append(classLine).append("\n");
        }

StringBuilder会以某种方式改善您的表现。