String.split()将原始的char数组保留在里面

时间:2012-09-02 17:39:05

标签: java string split substring deep-copy

我注意到Java String会在其中重用char数组,以避免在诸如subString()之类的方法中为新的String实例创建新的char数组。为此,String中有几个取消发布的构造函数,接受一个char数组和两个int作为范围来构造一个String实例。

但直到今天我发现split还将重用原始String实例的char arr。现在我从一个文件中读取一个loooooong行,用“,”拆分它,并为实际用法剪切一个极限列。因为线的每个部分都秘密地拿着looooong char数组的参考,我很快就得到了一个OOO。

这是示例代码:

ArrayList<String> test = new ArrayList<String>(3000000);
BufferedReader origReader = new BufferedReader(new FileReader(new File(
        "G:\\filewithlongline.txt")));
String line = origReader.readLine();
int i = 0;
while ((line = origReader.readLine()) != null) {
    String name = line.split(',')[0];
    test.add(name);
    i++;
    if (i % 100000 == 0) {
        System.out.println(name);
    }
}
System.out.println(test.size());

JDK中是否有任何标准方法可以确保吐出的每个String实例都是“真正的深拷贝”而不是“浅拷贝”?

现在我正在使用一种非常难看的解决方法来强制创建一个新的String实例:

ArrayList<String> test = new ArrayList<String>(3000000);
BufferedReader origReader = new BufferedReader(new FileReader(new File(
        "G:\\filewithlongline.txt")));
String line = origReader.readLine();
int i = 0;
while ((line = origReader.readLine()) != null) {
    String name = line.split(',')[0]+"  ".trim(); // force creating a String instance
    test.add(name);
    i++;
    if (i % 100000 == 0) {
        System.out.println(name);
    }
}
System.out.println(test.size());

2 个答案:

答案 0 :(得分:3)

最简单的方法是直接创建一个新的String。这是一个很好的主意的罕见案例之一。

String name = new String(line.split(",")[0]); // note the use of ","

另一种方法是自己解析文件。

do {
    StringBuilder name = new StringBuilder();
    int ch;
    while((ch = origReader.read()) >= 0 && ch != ',' && ch >= ' ') {
       name.append((char) ch);
    }
    test.add(name.toString());
} while(origReader.readLine() != null);

答案 1 :(得分:2)

Stringcopy constructor可用于此目的。

final String name = new String(line.substring(0, line.indexOf(',')));

...或者,正如彼得所建议的那样,只需阅读,

final StringBuilder buf = new StringBuilder();
do {
  int ch;
  while ((ch = origReader.read()) >= 0 && ch != ',') {
    buf.append((char) ch);
  }
  test.add(buf.toString());
  buf.setLength(0);
} while (origReader.readLine() != null);