1

我正在阅读一个 csv 文件,它有大约 50,000 行和 1.1MiB 大小(并且可以变得更大)。

在 Code1 中,我使用 String 来处理 csv,而在 Code2 中,我使用 StringBuilder(只有一个线程执行代码,所以没有并发问题)

使用 StringBuilder 会使使用普通 String 类的代码更难阅读。

我是否在 Code2 中过早地使用 StringBuilder 优化事物以节省一些堆空间和内存?

代码1

            fr = new FileReader(file);
            BufferedReader reader = new BufferedReader(fr);

            String line = reader.readLine();
                while ( line != null )
                {
                    int separator = line.indexOf(',');
                    String symbol = line.substring(0, seperator);
                    int begin = separator;
                    separator = line.indexOf(',', begin+1);
                    String price = line.substring(begin+1, seperator);

                    // Publish this update
                    publisher.publishQuote(symbol, price);

                    // Read the next line of fake update data
                    line = reader.readLine();
                 }

代码2

                    fr = new FileReader(file);
                    StringBuilder stringBuilder = new StringBuilder(reader.readLine());

                while( stringBuilder.toString() != null ) {
                    int separator = stringBuilder.toString().indexOf(',');
                    String symbol = stringBuilder.toString().substring(0, separator);
                    int begin = separator;
                    separator = stringBuilder.toString().indexOf(',', begin+1);
                    String price = stringBuilder.toString().substring(begin+1, separator);
                    publisher.publishQuote(symbol, price);

                    stringBuilder.replace(0, stringBuilder.length(), reader.readLine());
                }

编辑

我消除了 toString() 调用,因此产生的字符串对象会更少。

代码3

while( stringBuilder.length() > 0 ) {
                    int separator = stringBuilder.indexOf(",");
                    String symbol = stringBuilder.substring(0, separator);
                    int begin = separator;
                    separator = stringBuilder.indexOf(",", begin+1);
                    String price = stringBuilder.substring(begin+1, separator);
                    publisher.publishQuote(symbol, price);
                    Thread.sleep(10);
                    stringBuilder.replace(0, stringBuilder.length(), reader.readLine());
                }

另外,原始代码是从http://www.devx.com/Java/Article/35246/0/page/1下载的

4

5 回答 5

3

优化的代码会提高应用程序的性能吗?- 我的问题

第二个代码示例不会为您节省任何内存或任何计算时间。恐怕您可能误解了 的目的StringBuilder,它实际上是用来构建字符串的——而不是阅读它们。

在循环或您的第二个代码示例中,每一行都包含表达式,本质上是将缓冲的字符串一遍又一遍地stringBuilder.toString()变成一个对象。String您的实际字符串操作是针对这些对象完成的。第一个代码示例不仅更易于阅读,而且肯定是两者中的佼佼者。

我是否过早地使用 StringBuilder 优化事物?- 你的问题

除非您已经分析了您的应用程序并得出结论,这些行会导致执行速度显着减慢,否则的。除非您确实确定某些事情会很慢(例如,如果您认识到计算复杂度很高),否则您肯定希望在开始进行会损害代码可读性的优化之前进行一些分析。

可以对这段代码进行哪些优化?- 我的问题

如果您已经对应用程序进行了概要分析,并认为这是进行优化的正确位置,那么您应该考虑查看Scanner该类提供的功能。实际上,这可能会给您带来更好的性能(分析会告诉您这是否属实)和更简单的代码。

于 2010-04-07T14:53:55.667 回答
2

我是否在 Code2 中过早地使用 StringBuilder 优化事物以节省一些堆空间和内存?

最有可能:的。但是,只有一种方法可以找到:分析您的代码。

另外,我会使用适当的 CSV 解析器而不是你现在正在做的事情:http: //ostermiller.org/utils/CSV.html

于 2010-04-07T14:53:48.253 回答
1

Code2实际上比 Code1效率低,因为每次调用stringBuilder.toString()都是在创建一个新java.lang.String实例(除了现有StringBuilder对象之外)。由于对象创建开销,这在空间和时间方面效率较低。

将 的内容readLine()直接分配给 aString然后拆分String通常会足够高效。您也可以考虑使用Scanner该类。

节省内存的技巧

如果您在输入中遇到多个重复标记,请考虑使用 String.intern() 以确保每个相同的标记引用相同的 String 对象;例如

String[] tokens = parseTokens(line);
for (String token : tokens) {
  // Construct business object referencing interned version of token.
  BusinessObject bo = new BusinessObject(token.intern());
  // Add business object to collection, etc.
}
于 2010-04-07T14:52:29.907 回答
0

StringBuilder通常这样使用:

StringBuilder sb = new StringBuilder();
sb.append("You").append(" can chain ")
  .append(" your ").append(" strings ")
  .append("for better readability.");

String myString = sb.toString(); // only call once when you are done
System.out.prinln(sb); // also calls sb.toString().. print myString instead
于 2010-04-07T15:09:29.517 回答
0

StringBuilder 有几个好东西

  • StringBuffer 的操作是同步的,而 StringBuilder 不是,所以使用 StringBuilder 会提高单线程场景下的性能
  • 扩展缓冲区后,可以通过在对象上调用 setLength(0) 来重用缓冲区。有趣的是,如果您进入调试器并检查 StringBuilder 的内容,您会发现即使在调用 setLength(0) 之后内容仍然存在。JVM 只是重置字符串的指针开头。下次当您开始附加字符时,指针会移动
  • 如果您不确定字符串的长度,最好使用 StringBuilder,因为一旦扩展缓冲区,您可以将相同的缓冲区重用为更小或相同的大小

StringBuffer 和 StringBuilder 在所有操作中几乎相同,只是 StringBuffer 是同步的,而 StringBuilder 不是

如果您没有多线程,那么最好使用 StringBuilder

于 2010-04-07T16:47:50.967 回答