Java StringBuilder与考虑替换的字符串
在连接大量字符串时,建议我使用Java StringBuilder与考虑替换的字符串,java,string,replace,stringbuilder,Java,String,Replace,Stringbuilder,在连接大量字符串时,建议我使用StringBuilder这样做: StringBuilder someString = new StringBuilder("abc"); someString.append("def"); someString.append("123"); someString.append("moreStuff"); 相对于 String someString = "abc"; someString = someString + "def"; someString = so
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";
这将导致创建相当多的字符串,而不是一个
现在,我需要做一件类似的事情,但不是使用串联,而是使用字符串的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,并创建大量像上面那样的冗长行更好?”可能是String类内部使用的字符串 索引 方法查找旧字符串的索引并将其替换为新字符串
而且StringBuilder不是线程安全的,因此执行速度更快。StringBuilder确实比手动连接或修改字符串要好,因为StringBuilder是可变的,而字符串是不可变的,每次修改都需要创建一个新字符串 不过,请注意,Java编译器会自动转换如下示例:
String result = someString + someOtherString + anotherString;
someString = someString.replace("VARIABLE1", "abc");
someString = someString.replace("VARIABLE2", "xyz");
变成类似于:
String result = new StringBuilder().append(someString).append(someOtherString).append(anotherString).toString();
也就是说,除非您要替换大量字符串,选择可读性和可维护性更好的字符串。因此,如果您可以通过一系列的“替换”调用来保持它的简洁性,那么就通过StringBuilder方法来做吧。与处理压力相比,这种差异可以忽略不计
PS
对于您的代码示例(正如OscarRyz指出的,如果在someString
中有多个“$VARIABLE1”
,则该示例不起作用,在这种情况下,您需要使用循环),您可以缓存indexOf
调用的结果:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
与
无需搜索字符串两次:-)您可以编写一个方法来替换StringBuilder字符串的某些部分,而不是像这样的长行:
public StringBuilder replace(StringBuilder someString, String replaceWhat, String replaceWith) {
return someString.replace(someString.indexOf(replaceWhat), someString.indexOf(replaceWhat)+replaceWhat.length(), replaceWith);
}
如果您的字符串确实很大,并且您担心性能,我建议您编写一个类,该类接受模板文本和变量列表,然后逐个字符读取源字符串,并使用StringBuilder生成结果。在CPU和内存使用方面,这应该是最有效的。此外,如果您正在从文件中读取此模板文本,我不会预先将其全部加载到内存中。从文件中读取时,将其分块处理 如果您只是在寻找一种很好的方法来构建一个字符串,它的效率不如StringBuilder,但比反复追加字符串更有效,那么您可以使用它。它的工作原理与C中的sprintf()类似。也是一个选项,但它使用StringBuffer
这里还有另一个相关的问题:猜怎么着?如果您使用Java 1.5+运行,那么连接对字符串文本的作用是相同的
String h = "hello" + "world";
及
都是一样的
那么,编译器已经为您完成了这项工作
当然,最好是:
String j = "hellworld"; // ;)
至于第二个,是的,这是首选,但不应该那么难,具有“搜索和替换”的功能和一点regex-foo
例如,您可以定义一个类似于此示例中的方法:
public static void replace( String target, String replacement,
StringBuilder builder ) {
int indexOfTarget = -1;
while( ( indexOfTarget = builder.indexOf( target ) ) >= 0 ) {
builder.replace( indexOfTarget, indexOfTarget + target.length() , replacement );
}
}
您的代码当前如下所示:
String result = someString + someOtherString + anotherString;
someString = someString.replace("VARIABLE1", "abc");
someString = someString.replace("VARIABLE2", "xyz");
你所要做的就是抓取文本编辑器一个触发器,比如vi搜索和替换:
%s/^.*("\(.*\)".\s"\(.*\)");/replace("\1","\2",builder);
上面写着:“把括号中任何看起来像字符串文字的东西放在另一个字符串中。”
您的代码将如下所示:
someString = someString.replace("VARIABLE1", "abc");
someString = someString.replace("VARIABLE2", "xyz");
为此:
replace( "VARIABLE1", "abc", builder );
replace( "VARIABLE2", "xyz", builder );
很快
这是一个有效的演示:
class DoReplace {
public static void main( String ... args ) {
StringBuilder builder = new StringBuilder(
"LONG CONSTANT WITH VARIABLE1 and VARIABLE2 and VARIABLE1 and VARIABLE2");
replace( "VARIABLE1", "abc", builder );
replace( "VARIABLE2", "xyz", builder );
System.out.println( builder.toString() );
}
public static void replace( String target, String replacement,
StringBuilder builder ) {
int indexOfTarget = -1;
while( ( indexOfTarget = builder.indexOf( target ) ) > 0 ) {
builder.replace( indexOfTarget, indexOfTarget + target.length() ,
replacement );
}
}
}
我想说的是使用StringBuilder,但只需编写一个包装器,使代码更具可读性,从而更易于维护,同时保持效率=D
import java.lang.StringBuilder;
public class MyStringBuilder
{
StringBuilder sb;
public MyStringBuilder()
{
sb = new StringBuilder();
}
public void replace(String oldStr, String newStr)
{
int start = -1;
while ((start = sb.indexOf(oldStr)) > -1)
{
int end = start + oldStr.length();
sb.replace(start, end, newStr);
}
}
public void append(String str)
{
sb.append(str);
}
public String toString()
{
return sb.toString();
}
//.... other exposed methods
public static void main(String[] args)
{
MyStringBuilder sb = new MyStringBuilder();
sb.append("old old olD dudely dowrite == pwn");
sb.replace("old", "new");
System.out.println(sb);
}
}
输出:
new new olD dudely dowrite == pwn
现在,您可以只使用一个简单的衬里的新版本
MyStringBuilder mySB = new MyStringBuilder();
mySB.append("old dudley dowrite == pwn");
mySB.replace("old", "new"):
所有人的代码都有一个bug。试试你的替换(“x”,“xy”)。它将无限循环。Jam Hong是正确的-上述解决方案都包含无限循环的可能性。我想这里要吸取的教训是,微观优化往往会导致各种可怕的问题,并不会真正为你节省太多。尽管如此,这是一个不会无限循环的解决方案
private static void replaceAll(StringBuilder builder, String replaceWhat, String replaceWith){
int occuranceIndex = builder.indexOf(replaceWhat);
int lastReplace = -1;
while(occuranceIndex >= 0){
if(occuranceIndex >= lastReplace){
builder.replace(occuranceIndex, occuranceIndex+replaceWhat.length(), replaceWith);
lastReplace = occuranceIndex + replaceWith.length();
occuranceIndex = builder.indexOf(replaceWhat);
}else{
break;
}
}
}
虽然微优化确实会有问题,但有时这取决于上下文,例如,如果您的替换恰好在一个10000次迭代的循环中运行,那么您将看到与“无用”优化的显著性能差异
但是,在大多数情况下,最好是在可读性方面出错如果输入中有两个$VARIABLE1,则此操作失败(它只替换了第一个。你必须把它放在一个while循环中。@OscarRyz D'oh!是的。我甚至没有注意到:-p。我编写代码示例的主要原因只是向提问者指出,他们不应该调用indexOf两次。顺便说一句,这是一个很好的观点。我在一个示例中尝试了同样的方法,直到那时才意识到。这很容易伪造。)t、 看我的ans@OscarRyz@ZachL:Example:
builder=newstringbuilder(120);builder.append(a()).append(b()).append(c())
Hi,如果我们知道最终的大小,比如说输出字符串将是120,那么上面的代码会比编译过程中自动生成的代码更好吗。注意,方法a、b、c不会返回静态硬编码字符串,所以编译器无法知道初始化生成器时使用的值。如果生成性能问题,请更改它。如果没有更重要的更改要执行,请更改它。如果输入非常大并且经常使用,请更改它。顺便说一句,secont方法不起作用,因为它只会替换它一次,您必须将它放在一个while循环中。看看我的答案。我也在考虑相同的问题,但这需要一个while循环来替换它们,不仅如此