在连接大量字符串时,我建议使用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,并且有很多冗长的线条,例如上面那个?”
答案 0 :(得分:44)
确实,StringBuilder往往比手动连接或修改字符串更好,因为StringBuilder是可变的,而String是不可变的,你需要为每个修改创建一个新的字符串。
但请注意,Java编译器会自动转换如下示例:
String result = someString + someOtherString + anotherString;
成像:
String result = new StringBuilder().append(someString).append(someOtherString).append(anotherString).toString();
也就是说,除非你要更换很多字符串,否则会选择更具可读性和更易维护的字符。所以如果你可以通过一系列“替换”调用来保持它更清洁,继续这样做,通过StringBuilder方法。与您在处理the sad tragedy of micro-optimizations时节省的压力相比,差异可以忽略不计。
PS
对于您的代码示例(正如OscarRyz所指出的那样,如果"$VARIABLE1"
中有多个someString
,则无法使用,在这种情况下,您需要使用循环),您可以将indexOf
调用的结果缓存在:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
使用
int index = someString.indexOf("$VARIABLE1");
someString.replace(index, index+10, "abc");
无需搜索字符串两次: - )
答案 1 :(得分:7)
String h = "hello" + "world";
和
String i = new StringBuilder().append("hello").append("world").toString();
是一样的。
所以,编译器已经为你完成了工作。
当然更好的是:
String j = "hellworld"; // ;)
至于第二个,是的,这是首选,但不应该那么难,有“搜索和替换”的力量和一点正则表达式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 );
}
}
您的代码目前看起来像这样:
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 );
}
}
}
答案 2 :(得分:3)
我想说使用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"):
答案 3 :(得分:1)
您可以编写一个替换StringBuilder字符串部分的方法,而不是像这样的长行,这就像这样:
public StringBuilder replace(StringBuilder someString, String replaceWhat, String replaceWith) {
return someString.replace(someString.indexOf(replaceWhat), someString.indexOf(replaceWhat)+replaceWhat.length(), replaceWith);
}
答案 4 :(得分:0)
可能是String Class内部使用
的indexOf
查找旧字符串索引的方法,并用新字符串替换它。
而且StringBuilder也不是线程安全的,所以它的执行速度要快得多。
答案 5 :(得分:0)
如果你的字符串真的很大并且你担心性能我会建议写一个带有模板文本和变量列表的类,然后逐个字符地读取源字符串并使用StringBuilder构建结果。在CPU和内存使用方面,这应该是最有效的。此外,如果您正在从文件中读取此模板文本,我不会将其全部加载到内存中。当你从文件中读取它时,以块的形式处理它。
如果您只是在寻找一种很好的方法来构建一个不如StringBuilder那么高效的字符串,但是比一遍又一遍地追加字符串更有效率,您可以使用String.format()。它的作用类似于C中的sprintf()。MessageFormat.format()也是一个选项,但它使用StringBuffer。
此处还有另一个相关问题:Inserting a Java string in another string without concatenation?
答案 6 :(得分:0)
所有人的代码都有错误。严重 yourReplace("x","xy")
。循环无限
答案 7 :(得分:0)
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;
}
}
}
答案 8 :(得分:0)
虽然微优化可能有问题,但它有时取决于上下文,例如,如果你的替换恰好在10000次迭代的循环中运行,你会看到与"无用"优化
但是,在大多数情况下,最好在可读性方面犯错误