Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用非常大的字符串不好?(爪哇)_Java - Fatal编程技术网

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,做得好。数字永远是最好的答案。顺便说一句,我重新运行了你的测试,重构了两个测试,多次运行(以避免任何可能的类加载延迟)。听到我得到了与你非常相似的结果,你不会感到惊讶。