使用StringBuilder处理csv文件以节省堆空间

时间:2010-04-07 14:50:25

标签: java heap stringbuilder

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

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

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

我是否过早使用Code2中的StringBuilder进行优化以节省一些堆空间和内存?

Code1

            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()调用,因此会产生更少的字符串对象。

CODE3

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

下载的

5 个答案:

答案 0 :(得分:3)

  

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

第二个代码示例将保存任何内存或任何计算时间。我担心你可能误解了StringBuilder的目的,这本身就是用来构建字符串 - 而不是阅读它们。

在循环或第二个代码示例中,每一行都包含表达式stringBuilder.toString(),实际上反复将缓冲的字符串转换为String对象。您的实际字符串操作是针对这些对象完成的。第一个代码示例不仅更容易阅读,而且肯定是两者的兼容性。

  

我是否过早使用StringBuilder进行优化? - 您的问题

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

  

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

如果您已对应用程序进行了分析,并确定这是进行优化的正确位置,则应考虑查看Scanner类提供的功能。实际上,这可能会为您提供更好的性能(分析会告诉您这是否属实)以及更简单的代码。

答案 1 :(得分:2)

  

我是否过早使用Code2中的StringBuilder进行优化以节省一些堆空间和内存?

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

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

答案 2 :(得分:1)

Code2实际上效率低,因为每次拨打stringBuilder.toString()时,您都会创建一个新的java.lang.String实例(除了现有的StringBuilder宾语)。由于对象创建开销,这在空间和时间方面效率较低。

readLine()的内容直接分配给String,然后将String分开,通常会有足够的效果。您还可以考虑使用Scanner类。

内存节省提示

如果在输入中遇到多个重复令牌,请考虑使用String.intern()来确保每个相同的令牌引用相同的String对象; e.g。

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.
}

答案 3 :(得分: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

答案 4 :(得分:0)

StringBuilder有几件好事

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

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

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