Java 使用非常大的字符串不好?(爪哇)
创造巨大的字符串有什么负面影响吗?例如,如果我们从一个潜在的巨大文本文件中读取文本:Java 使用非常大的字符串不好?(爪哇),java,Java,创造巨大的字符串有什么负面影响吗?例如,如果我们从一个潜在的巨大文本文件中读取文本: while (scanner.hasNext()) { someString += scanner.next(); } // do something cool with someString 逐行处理文件(通常)是更好的解决方案吗?为什么 谢谢使用StringBuilder。您的方法可能会创建数千个一次性对象。字符串是不可变的对象,这意味着一旦创建了一个字符串,就无法更改它。。。您只能创建新字符串并将引
while (scanner.hasNext()) {
someString += scanner.next();
}
// do something cool with someString
逐行处理文件(通常)是更好的解决方案吗?为什么
谢谢使用StringBuilder。您的方法可能会创建数千个一次性对象。字符串是不可变的对象,这意味着一旦创建了一个字符串,就无法更改它。。。您只能创建新字符串并将引用分配给当前实例。StringBuilder的速度和内存效率将提高数百倍甚至数千倍
不过,大多数Java编译器现在都会为您优化,但最好先编写代码。我相信每次执行+=,都会创建一个新的字符串对象。改用
StringBuilder
。流媒体与非流媒体的比较
当您可以流式传输时,您可以处理任何大小的文件(假设您真的可以忘记您已经看到的所有数据)。你会得到一个自然的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");
}
}
正如Jon Skeet所说,流式处理是一种更健壮的数据处理方式。此外,字符串的最大大小是Max的字符,因此如果文件可能大于它,则应该考虑在所有可能的情况下处理数据流。 < P>如果输入大于系统的内存(例如,输入是由另一台计算机通过HTTP连接生成的),会怎样?如果您一次处理一行,那么您总是在取得进展,并且您最终将处理整个输入,假设输入是有限的。但是,如果在执行任何处理之前等待查看整个输入,则会耗尽内存并中断
通常,以流方式处理数据是好的。如果可能,这也适用于使用迭代器而不是随机访问执行处理。它将允许你的程序扩展到非常大的输入大小,并且它也允许你的程序被流水线化(即另一个程序可以开始处理你的程序输出,而你的程序仍然处于处理它自己的输入的中间)。在当今许多不同计算机之间进行大媒体传输的时代,支持这一点几乎总是一个好主意。还有几点:
StringBuilder
,然后调用toString()
,JVM将在转换过程中临时需要两倍的char[]
存储空间。如果可以将数据处理为CharSequence
(StringBuilder
实现CharSequence
),则可以避免这种情况字符串
表示为单词列表(即列表
),并对每个单词调用intern()
。如果数据包含大量重复的单词,则表示显著节省了内存StringBuilder甚至更好-没有同步。错误。编译代码并查看字节码。根据具体情况,您可以使用缓冲区或生成器。@iftrue:错误。请看您答案上的回复。我认为(Java->bytecode)编译器优化不会对提供的代码产生太大影响。错误。编译代码并查看字节码。请参阅我的回答。具体取决于编译器。大多数编译器仅在StringBuilder位于同一行(例如“123”+“456”+“789”)时替换为StringBuilder。不是我所看到的。我在某个地方有一篇文章,但我把它丢了。@Ifrue:我们对它进行基准测试怎么样?你似乎完全相信StringBuilder是无用的,尽管编译后的代码在每次迭代中都会创建一个新的StringBuilder,并在每次迭代中调用toString。是时候进行测试了……对编译器优化的评论很好。然而,我仍然认为这个答案是正确的-我认为最好不要不必要地依赖于特定于实现的编译器优化。编译这个!它会变成StringBuilder!@iftrue:它会变成StringBuilder的使用,然后调用toString。但这是一个初学者的问题,很遗憾他回答了这个问题。@01:我不明白你的意思评论。你能详细说明一下吗?Jon,做得好。数字永远是最好的答案。顺便说一句,我重新运行了你的测试,重构了两个测试,多次运行(以避免任何可能的类加载延迟)。听到我得到了与你非常相似的结果,你不会感到惊讶。