StringBuilder 与 String 考虑替换
在连接大量字符串时,建议我使用 StringBuilder
来实现:
StringBuilder someString = new StringBuilder("abc");
someString.append("def");
someString.append("123");
someString.append("moreStuff");
与此相反,
String someString = "abc";
someString = someString + "def";
someString = someString + "123";
someString = someString + "moreStuff";
这会导致创建相当多的字符串,而不是一个。
现在,我需要做一件类似的事情,但我不使用串联,而是使用 String 的 replace
方法,如下所示:
String someString = SOME_LARGE_STRING_CONSTANT;
someString = someString.replace("$VARIABLE1", "abc");
someString = someString.replace("$VARIABLE2", "def");
someString = someString.replace("$VARIABLE3", "123");
someString = someString.replace("$VARIABLE4", "moreStuff");
要使用 StringBuilder 完成同样的事情,我必须这样做,只是为了一次替换:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
所以我的问题是:“是使用 String.replace 并创建大量额外的字符串更好,还是仍然使用 StringBuilder 并创建大量冗长的行(如上面的行)更好?”
When doing concatenating lots of strings, I have been recommended to do it using a StringBuilder
as such:
StringBuilder someString = new StringBuilder("abc");
someString.append("def");
someString.append("123");
someString.append("moreStuff");
as opposed to
String someString = "abc";
someString = someString + "def";
someString = someString + "123";
someString = someString + "moreStuff";
which would result in the creation of quite a few Strings, as opposed to one.
Now, I need to do a similar thing, but instead of using concatenation I use the replace
method of String as such:
String someString = SOME_LARGE_STRING_CONSTANT;
someString = someString.replace("$VARIABLE1", "abc");
someString = someString.replace("$VARIABLE2", "def");
someString = someString.replace("$VARIABLE3", "123");
someString = someString.replace("$VARIABLE4", "moreStuff");
To accomplish the same thing using StringBuilder, I have to do this, just for one replace:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
So my question is: "Is it better to use String.replace and have lots of extra Strings created, or to use StringBuilder still, and have lots of long winded lines such as the one above?"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
你猜怎么着?如果您使用 Java 1.5+ 运行,则连接的工作方式与字符串文字相同
,并且
是相同的。
所以,编译器已经为你完成了这项工作。
当然更好的是:
至于第二个,是的,这是首选,但应该不那么难,具有“搜索和替换”的功能和一些正则表达式 foo
例如,您可以定义一个类似中的方法这个示例:
您的代码当前看起来像这样:
您所要做的就是抓住文本编辑器的触发器,例如 vi 搜索和替换:
读取:“采取括号中的任何内容,看起来像字符串文字,并且把它放在另一个字符串中”。
你的代码很快就会从这个:
变成这个:
。
这是一个工作演示:
Guess what? If you are running with Java 1.5+ the concatenation works the same with string literals
and
Are the same.
So, the compiler did the work for you already.
Of course better would be:
As for the second, yeap, that's preferred, but should't be that hard, with the power of "search and replace" and a bit of regex foo
For instance you can define a method like the one in this sample:
And your code currently looks like this:
All you have to do is grab text editor an trigger something like this vi search and replace:
That read: "take anything in parenthesis and that looks like a string literal, and put it in this other string".
And your code will look from this:
to this:
In no time.
Here's a working demo:
我会说使用 StringBuilder,但只需编写一个包装器,使代码更具可读性,从而更易于维护,同时仍然保持效率。 =D
输出:
现在您可以使用新版本,这是一个简单的衬垫
I would say go for using StringBuilder but simply write a wrapper that facilitates making the code more readable and thus more maintainable, while still maintaining efficiency. =D
OUTPUT:
Now you can just use the new version that is one easy liner
您可以编写一个方法来替换 StringBuilder 字符串的一部分,而不是使用这样的长行,大致如下:
Instead of having long lines like that, you could just write a method for replacing parts of StringBuilder strings, something along the lines of this:
可能是 String 类内部使用
方法查找旧字符串的索引并将其替换为新字符串。
而且 StringBuilder 不是线程安全的,因此执行速度要快得多。
May be the String Class internally uses
method to find index of old string and replace it with new string.
And also StringBuilder is not threadsafe so it executes much faster.
如果您的字符串确实很大并且您担心性能,我建议您编写一个类,该类采用模板文本和变量列表,然后逐个字符读取源字符串并使用 StringBuilder 构建结果。就 CPU 和内存使用而言,这应该是最高效的。另外,如果您从文件中读取此模板文本,我不会预先将其全部加载到内存中。当您从文件中读取它时,对其进行分块处理。
如果您只是在寻找一种构建字符串的好方法,该方法的效率不如 StringBuilder 但比一遍又一遍地附加字符串更有效,您可以使用 String.format()。它的工作方式类似于 C 语言中的 sprintf()。 MessageFormat.format() 也是一个选项,但它使用 StringBuffer。
这里还有另一个相关问题: Inserting a Java string in another string没有串联?
If your string really is large and you're worried about performance I would recommend writing a class which takes your template text and a list of variables, then reads over the source string character by character and builds the result using StringBuilder. That should be the most efficient both in terms of CPU and memory usage. Also, if you are reading this template text from a file I wouldn't load it all into memory up front. Process it in chunks as you read it from the file.
If you're just looking for a nice way to build a string that's not quite as efficient as StringBuilder but more efficient than appending strings over and over you can use String.format(). It works like sprintf() in C. MessageFormat.format() is an option too but it uses StringBuffer.
There is another related question here: Inserting a Java string in another string without concatenation?
所有家伙的代码都有一个错误。尝试
yourReplace("x","xy")
。它会无限循环All guys' codes have a bug .try
yourReplace("x","xy")
.It will loop infinitelyJam Hong 是正确的 - 上述解决方案都包含无限循环的潜力。我想这里要吸取的教训是,微观优化通常会导致各种可怕的问题,而且并不能真正为您节省太多。尽管如此,这是一个不会无限循环的解决方案。
Jam Hong is correct - the above solutions all contain the potential to loop infinitely. I guess the lesson to take away here is that micro optimisations can often cause all sorts of horrible issues and don't really save you much. Still, be that as it may - here is a solution that will not infinite loop.
虽然微观优化确实可能存在问题,但它有时取决于上下文,例如,如果您的替换恰好在具有 10000 次迭代的循环内运行,您将看到与“无用”优化的显着性能差异。
但在大多数情况下,最好在可读性方面犯错误
while it's true that micro optimizations can be problematic, it sometimes depends on the context, for instance, if your replace happens to run inside of a loop with 10000 iterations, your will see a significant performance difference from the "useless" optimizations.
in most cases however, it's best to err on the side of readability
确实,StringBuilder 往往比手动连接或修改 String 更好,因为 StringBuilder 是可变的,而 String 是不可变的,您需要为每次修改创建一个新的 String。
但需要注意的是,Java 编译器会自动将这样的示例转换为:
转换为类似的内容:
也就是说,除非您要替换大量字符串,否则选择更具可读性和更可维护性的那个。微优化的悲惨悲剧。
PS
对于您的代码示例(正如 OscarRyz 指出的那样,如果
someString
中有多个"$VARIABLE1"
,则该代码示例将不起作用,在这种情况下,您将需要使用循环),您可以将indexOf
调用的结果缓存在:不需要
搜索字符串两次:-)
It is true that StringBuilder tends to be better than concatenating or modifying Strings manually, since StringBuilder is mutable, while String is immutable and you need to create a new String for each modification.
Just to note, though, the Java compiler will automatically convert an example like this:
into something like:
That said, unless you're replacing a whole lot of Strings, go for whichever is more readable and more maintainable. So if you can keep it cleaner by having a sequence of 'replace' calls, go ahead and do that over the StringBuilder method. The difference will be negligible compared to the stress you save from dealing with the sad tragedy of micro-optimizations.
PS
For your code sample (which, as OscarRyz pointed out, won't work if you have more than one
"$VARIABLE1"
insomeString
, in which case you'll need to use a loop), you could cache the result of theindexOf
call in:With
No need to search the String twice :-)