То 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";
что привело бы к созданию довольно много строк, в отличие от одного.
теперь мне нужно сделать аналогичную вещь, но вместо использования конкатенации я использую 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");
поэтому мой вопрос: "лучше ли использовать строку.заменить и создать много дополнительных строк или использовать StringBuilder и иметь много длинных строк, таких как выше?"
9 ответов
верно, что StringBuilder имеет тенденцию быть лучше, чем конкатенация или изменение строк вручную, поскольку StringBuilder является изменяемым, в то время как String является неизменяемым, и вам нужно создать новую строку для каждой модификации.
просто обратите внимание, что компилятор Java автоматически преобразует такой пример:
String result = someString + someOtherString + anotherString;
в что-то вроде:
String result = new StringBuilder().append(someString).append(someOtherString).append(anotherString).toString();
это сказало, если вы не заменяете много строк,пойти на какой более читаемый и более ремонтопригодный. поэтому, если вы можете сохранить его чище, имея последовательность вызовов "replace", продолжайте и делайте это по методу StringBuilder. Разница будет незначительной по сравнению со стрессом, который вы спасаете от борьбы с печальная трагедия микро-оптимизаций.
PS
для вашего образца кода (который, как отметил Оскаррис, не будет работать, если у вас есть более одного "$VARIABLE1"
на someString
, в этом случае вам нужно будет использовать loop), вы можете кэшировать результат indexOf
звонок в:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
С
int index = someString.indexOf("$VARIABLE1");
someString.replace(index, index+10, "abc");
нет необходимости искать строку дважды : -)
угадайте, что? Если вы работаете с Java 1.5+, конкатенация работает одинаково со строковыми литералами
String h = "hello" + "world";
и
String i = new StringBuilder().append("hello").append("world").toString();
то же самое.
Итак, компилятор уже сделал работу за вас.
конечно лучше было бы:
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 );
}
}
и ваш код в настоящее время выглядит так:
someString = someString.replace("VARIABLE1", "abc");
someString = someString.replace("VARIABLE2", "xyz");
все, что вам нужно сделать, это захватить текстовый редактор триггер что-то вроде этого поиска vi и заменить:
%s/^.*("\(.*\)".\s"\(.*\)");/replace("","",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"):
вместо таких длинных строк вы можете просто написать метод для замены частей строк StringBuilder, что-то вроде этого:
public StringBuilder replace(StringBuilder someString, String replaceWhat, String replaceWith) {
return someString.replace(someString.indexOf(replaceWhat), someString.indexOf(replaceWhat)+replaceWhat.length(), replaceWith);
}
может быть класс String внутренне использует
indexOf
метод для поиска индекса старой строки и замены его новой строкой.
а также StringBuilder не является threadsafe, поэтому он выполняется намного быстрее.
Если ваша строка действительно большая, и вы беспокоитесь о производительности, я бы рекомендовал написать класс, который принимает текст шаблона и список переменных, а затем читает исходный символ строки по символу и строит результат с помощью StringBuilder. Это должно быть наиболее эффективным как с точки зрения процессора и памяти. Кроме того, если Вы читаете этот текст шаблона из файла, я бы не загружал его все в память спереди. Обработайте его в кусках, как Вы читаете его из файл.
Если вы просто ищете хороший способ построить строку, которая не так эффективна, как StringBuilder, но более эффективна, чем добавление строк снова и снова, вы можете использовать строку.format (). Он работает как sprintf() в с. messageformat значение.format () тоже вариант, но он использует StringBuffer.
здесь есть еще один связанный с этим вопрос:вставка строки Java в другую строку без конкатенации?
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 итерациями, вы увидите значительную разницу в производительности от "бесполезных" оптимизаций.
в большинстве случаев, однако, лучше всего ошибаться на стороне читаемости