如何在不创建新对象的情况下修剪java中的字符串?

如何在不创建新对象的情况下修剪java中的字符串?,java,string,trim,Java,String,Trim,我有一个大的文本文件(大约2000万行),其中有以下格式的行: <string1>, <string2> , 现在,这些字符串可能有尾随或前导空格,我想在读取文件时删除这些空格 为此,我目前正在使用trim(),但由于Java中的字符串是不可变的,trim()正在为每个trim操作创建一个新对象。 这会导致太多的内存浪费 如何做得更好?您可以将字符串作为字符流读取,并记录要解析的每个标记的开始和结束位置 这仍然会为每个令牌创建一个对象,但如果令牌相对较长,则对象将包含

我有一个大的文本文件(大约2000万行),其中有以下格式的行:

<string1>, <string2>
现在,这些字符串可能有尾随或前导空格,我想在读取文件时删除这些空格

为此,我目前正在使用
trim()
,但由于Java中的字符串是不可变的,
trim()
正在为每个trim操作创建一个新对象。 这会导致太多的内存浪费


如何做得更好?

您可以将字符串作为字符流读取,并记录要解析的每个标记的开始和结束位置

这仍然会为每个令牌创建一个对象,但如果令牌相对较长,则对象将包含的两个
int
字段比相应的字符串小得多


但是,在你开始这段旅程之前,你可能应该确保你没有保留修剪过的字符串超过需要的时间。

假设你有一个
字符串
包含
,并且你只想拆分它而不修剪部分:

String trimmedBetween(String str, int start, int end) {
  while (start < end && Character.isWhitespace(str.charAt(start)) {
    ++start;
  }

  while (start < end && Character.isWhitespace(str.charAt(end - 1)) {
    --end;
  }

  return str.substring(start, end);
}

我认为您可以直接将结果数据写入新文件

String originStr = "   xxxxyyyy";
for (int i = 0; i < originStr.length(); i++) {
    if (' ' == originStr.charAt(i)) {
        continue;
    }
    NewFileOutPutStream.write(originStr.charAt(i));
}
String originStr=“xxxxyyyy”;
对于(int i=0;i
如果不可变的
字符串
类导致问题,我会感到惊讶;JVM非常高效,是多年工程工作的结果

这就是说,Java确实提供了一个用于操作字符串的可变类,称为
StringBuilder
。你可以看这些文件


如果您正在跨线程工作,.

正如您已经注意到的,字符串是不可变的。因此,解决方案不是使用字符串,而是使用可变的东西
StringBuffer
是一个合适的类

但是,StringBuffer不包括修剪方法,因此您可以使用以下方法:

void trim(StringBuffer sb) {
    int start = 0;
    while (sb.length() > start && Character.isWhitespace(sb.charAt(0))) {
        start++;
    }
    sb.delete(0, start - 1);

    int end = 0;
    while (sb.length() > end && Character.isWhitespace(sb.charAt(sb.length() - 1))) {
        end++;
    }
    sb.delete(sb.length() - end, sb.length() - 1);
}

如果要避免使用
String
,则必须使用
char
StringBuilder
自行处理,如下所示:

public class Test {
    public static void main(String... args) throws Exception {
        InputStreamReader in = new InputStreamReader(new FileInputStream("<testfile>"), "UTF-8");

        char[] buffer = new char[32768];
        int read = -1;
        int index;
        StringBuilder content = new StringBuilder();
        while ((read = in.read(buffer)) > -1) {
            content.append(buffer, 0, read);
            index = 0;
            while (index > -1) {
                index = content.indexOf("\n");
                if (index > -1) {
                    char[] temp = new char[index];
                    content.getChars(0, index, temp, 0);
                    handleLine(temp);
                    content.replace(0, index + 1, "");
                }
            }
        }

        in.close();
    }

    private static void handleLine(char[] line) {
        StringBuilder content = new StringBuilder().append(line);
        int start = 0;
        int end = content.length();
        if (end > 0) {
            char ch = content.charAt(0);
            while (Character.isWhitespace(content.charAt(start))) {
                start++;
                if (end <= start) {
                    break;
                }
            }
            if (start < end) {
                while (Character.isWhitespace(content.charAt(end - 1))) {
                    end--;
                    if (end <= start) {
                        break;
                    }
                }
            }
        }

        System.out.println("***" + content.subSequence(start, end) + "***");
    }
}
公共类测试{
公共静态void main(字符串…参数)引发异常{
InputStreamReader in=新的InputStreamReader(新文件InputStream(“”,“UTF-8”);
char[]buffer=新字符[32768];
int read=-1;
整数指数;
StringBuilder内容=新建StringBuilder();
while((read=in.read(buffer))>-1){
追加(缓冲区,0,读取);
指数=0;
而(索引>-1){
索引=content.indexOf(“\n”);
如果(索引>-1){
char[]temp=新字符[索引];
getChars(0,索引,temp,0);
扶手线(温度);
内容。替换(0,索引+1,“”);
}
}
}
in.close();
}
专用静态无效行(字符[]行){
StringBuilder内容=新建StringBuilder().append(行);
int start=0;
int end=content.length();
如果(结束>0){
char ch=content.charAt(0);
while(Character.isWhitespace(content.charAt(start))){
启动++;

如果(end我们可以用正则表达式处理

   {
    String str = "abcd, efgh";
    String [] result = str.split("(,\\s)|,");
    Arrays.asList(result).forEach(s -> System.out.println(s));
   }

请说明您是如何读取文件然后拆分字符串的。您确实意识到任何未使用的字符串都会被收集,因此没有真正的内存浪费,只有新创建的对象(由GC有效收集)。我不太确定,但我认为使用可以解决问题。显示您在文件中读取的代码;几乎完全确定,trim()将不会成为主内存瓶颈。使用逗号分隔符拆分字符串,然后使用StringBuilder追加每个字符串。因此,并非每次都像您所说的那样创建字符串。如果您使用m-thread模型,您可以将文件分隔,让它们成为逻辑上的几个块文件,然后上述方法也可以很好地工作。编写单个字符一次将花费永远的时间。您需要缓冲它。我确实想修剪部分,即单个字符串。为什么我要使用此修剪而不是默认修剪?目标是避免内存浪费,但您使用与内置
trim()
相同的额外内存(=返回新字符串),因为
string.trim()
仅从字符串的开头和结尾进行修剪。要使用此方法,必须拆分字符串(创建一个数组和两个字符串),然后修剪它们(最多两个字符串)。此方法只创建两个字符串,而不是4个字符串和一个数组。
   {
    String str = "abcd, efgh";
    String [] result = str.split("(,\\s)|,");
    Arrays.asList(result).forEach(s -> System.out.println(s));
   }