简体   繁体   English

ArrayList的高效转换 <String[]> 到JAVA中的多行字符串

[英]Efficient conversion of ArrayList<String[]> to multi-line String in JAVA

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";
}

My code is above. 我的代码在上面。 It works fine and produces exactly the result I want, just slowly. 它工作正常,产生我想要的结果,只是缓慢。 It takes about 10ms per item of ArrayList writtenClasses which is okay until I give it bigger jobs. 每个项目的ArrayList书写类需要大约10毫秒,这是好的,直到我给它更大的工作。 I suspect that there is something there to do with ArrayLists that is taking so long, but timing and printing to console job stats after each run revealed little. 我怀疑与ArrayLists有关的事情花了这么长时间,但是在每次运行之后,时间和打印到控制台工作统计数据都没有显示出来。

This above code is an adaptation of earlier code in hopes to improve efficiency. 上面的代码是对早期代码的改编,希望提高效率。 It does so by about 4%. 它的成功率约为4%。 The below code is the old method I used which takes just a little longer than the above. 下面的代码是我使用的旧方法,只需要比上面稍长的时间。

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

I do writtenClasses.set(writtenClasses.indexOf(classLines), null); writtenClasses.set(writtenClasses.indexOf(classLines), null); merely for the purposes of memory efficiency, and my stats show that it uses memory more efficiently with an undetectable amount of CPU effort. 仅仅是出于内存效率的目的,我的统计数据显示它在不可检测的CPU工作量下更有效地使用内存。

This is my second question here on StackOverflow and i've done my best to follow the rules, but if i'm asking this badly or being inadvertently inconsiderate in some way, please, highlight that to me and i'll address that. 这是我在StackOverflow上的第二个问题,我已经尽力遵守这些规则,但是如果我这么严重地问这个或者在某种程度上无意中不注意,请向我强调,我将解决这个问题。 :) :)

There is absolutely no use creating the intermediate processedClasses list. 创建中间的processedClasses列表绝对没有用。 Also, StringBuilder will speed up significantly the process: 此外, 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();

We build the content in a StringBuilder which implements the CharSequence interface. 我们在StringBuilder中构建内容,该StringBuilder实现CharSequence接口。 Many classes accept CharSequence s and not just String s. 许多类接受CharSequence而不仅仅是String A good example is a FileWriter . 一个很好的例子是FileWriter In these cases you don't even need to convert the StringBuilder to a String because the StringBuilder can be passed just as easily as its String result which may be another performance advantage if the content is really big. 在这些情况下,您甚至不需要将StringBuilder转换为String因为StringBuilder可以像String结果一样轻松地传递,如果内容非常大,这可能是另一个性能优势。

The problem has been pointed out by other answers. 其他答案已经指出了这个问题。 With Java 8, an alternative to the two nested loops and a StringBuilder is to use a stream and a joining collector*: 使用Java 8,两个嵌套循环和StringBuilder的替代方法是使用流和连接收集器*:

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

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

Not a proper answer, but too awkward to read in a comment: 不是一个正确的答案,但在评论中读得太尴尬:

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

That is creating a million String instances. 那就是创建了一百万个String实例。 I guess using a StringBuilder here should have a positive effect on performance. 我想在这里使用StringBuilder会对性能产生积极影响。

The main pain point here probably isn't the ArrayList , but the use of the + operator with String s. 这里的主要痛点可能不是ArrayList ,而是使用带+ String+运算符。 Since String s are immutable in java, each invocation forces the creation of a new object and copying of all the data, which, as you stated, may be quite long. 由于String在java中是不可变的,因此每次调用都会强制创建一个新对象并复制所有数据,正如您所说,这些数据可能会很长。

A faster way to do this would be to use a StringBuilder , which does not (necessarily) force the copying of the data on each operation: 更快的方法是使用StringBuilder ,它不必(必然)强制复制每个操作的数据:

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

based on this question 基于这个问题

ewall: 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 would somehow improve your performance. StringBuilder会以某种方式提高您的性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM