创建大字符串有什么负面影响吗?例如,如果我们从一个可能非常巨大的文本文件中读取文本:
while (scanner.hasNext()) {
someString += scanner.next();
}
// do something cool with some string
逐行处理文件是否(通常)是更好的解决方案,为什么?
创建大字符串有什么负面影响吗?例如,如果我们从一个可能非常巨大的文本文件中读取文本:
while (scanner.hasNext()) {
someString += scanner.next();
}
// do something cool with some string
逐行处理文件是否(通常)是更好的解决方案,为什么?
流式处理 vs 非流式处理
如果您使用流式处理,您可以处理任何大小的文件(假设您确实可以忘记已经查看的所有数据)。 您最终会得到一个自然的O(n)复杂度,这是非常好的。您不会因为内存不足而中断处理。
流式处理很棒... 但并不适用于每种情况。
StringBuilder
由于StringBuilder
建议存在一定争议,因此在此提供基准测试来展示其效果。为了让慢版本能够在合理的时间内完成,我不得不减少基准测试的大小。
首先是结果,然后是代码。 这是一个非常粗略的基准测试,但结果足以证明这一点...
c:\Users\Jon\Test>java Test slow
Building a string of length 120000 without StringBuilder took 21763ms
c:\Users\Jon\Test>java Test fast
Building a string of length 120000 with StringBuilder took 7ms
而且这段代码...
class FakeScanner
{
private int linesLeft;
private final String line;
public FakeScanner(String line, int count)
{
linesLeft = count;
this.line = line;
}
public boolean hasNext()
{
return linesLeft > 0;
}
public String next()
{
linesLeft--;
return line;
}
}
public class Test
{
public static void main(String[] args)
{
FakeScanner scanner = new FakeScanner("test", 30000);
boolean useStringBuilder = "fast".equals(args[0]);
// Accurate enough for this test
long start = System.currentTimeMillis();
String someString;
if (useStringBuilder)
{
StringBuilder builder = new StringBuilder();
while (scanner.hasNext())
{
builder.append(scanner.next());
}
someString = builder.toString();
}
else
{
someString = "";
while (scanner.hasNext())
{
someString += scanner.next();
}
}
long end = System.currentTimeMillis();
System.out.println("Building a string of length "
+ someString.length()
+ (useStringBuilder ? " with" : " without")
+ " StringBuilder took " + (end - start) + "ms");
}
}
我相信每次使用+=运算符会创建一个新的字符串对象。建议使用StringBuilder
代替。
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html
大多数Java编译器现在会为您优化代码,但最好的做法是一开始就编写正确的代码。
还有一些额外的要点:
StringBuilder
,然后调用 toString()
,JVM 在转换期间会暂时需要双倍的 char[]
存储空间。如果你可以将数据处理为 CharSequence
(StringBuilder
实现了 CharSequence
),那么就可以避免这种情况。String
表示为单词列表(即 List<String>
),并在每个单词上调用 intern()
。如果数据包含大量重复的单词,则这将表示显著的内存节省。