【问题标题】:String.split() will keep original char array insideString.split() 将保留原始字符数组
【发布时间】:2012-08-27 14:59:09
【问题描述】:

我注意到 Java String 将在其中重用 char 数组,以避免在 subString() 等方法中为新的 String 实例创建新的 char 数组。为此目的,String 中有几个 unpublish 构造函数,接受一个 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());

【问题讨论】:

  • 我真的很想知道 OOO 是什么
  • @SerkanArıkuşu OOO 这里的意思是内存不足。

标签: java string split substring deep-copy


【解决方案1】:

最简单的方法是直接创建一个新字符串。这是一个好主意的极少数情况之一。

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);

【讨论】:

  • 最后我找到了 String 有一个接受另一个 String 实例作为参数的构造函数的原因:-)。因此,需要从 split() 迭代 String 数组并为所需的列调用 new String()。有没有“deepSplit()”?
  • 我对你正在使用的那个循环感到困惑......一旦origReader.read返回-1并且内部循环退出,那么origReader.readLine肯定必须返回null
  • @veer 如果内循环在外循环中也停止。仅当最后一行没有 , 或新行时才会发生这种情况。
  • @PeterLawrey 输出将是无效的,因为您正在调用StringBuilder.append(int)。除此之外,我看不到你在哪里检查,,我仍然不明白这两个循环背后的逻辑。
  • @PeterLawrey new String() 听起来不错。它比自己解析更简单。谢谢!
【解决方案2】:

String 有一个 copy 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    • 2023-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    相关资源
    最近更新 更多