Конкатенация строк в Java StringBuilder - PullRequest
2 голосов
/ 25 марта 2011

У меня есть устаревший Java-файл, который использует конкатенацию строк для создания огромных объектов String. Это серьезная проблема с производительностью. Есть такой метод, который выполняет следующие действия:

String test="I am a very bad programmer"
+"to use concatenation"
+"Instead of StringBuilder"
+" or StringBuffer";

до

StringBuilder strBuilder= new StringBuilder();
strBuilder.append("I am a bad programmer");
strBuilder.append("to use concatenation");
strBuilder.append("Instead of StringBuilder");
strBuilder.append(" or StringBuffer");
String str= strBuilder.toString();

В основном мне нужна заглушка в Java только для того, чтобы передать в качестве входных данных экземпляр String и преобразовать его в StringBuilder. Кто-нибудь пробовал это в прошлом?

Ответы [ 4 ]

12 голосов
/ 25 марта 2011

Нет, это не проблема производительности. Если вы объединяете строку в строке (как вы показали), а не используете цикл, например, то компилятор автоматически преобразует + в StringBuilder. Проверьте документацию java.lang.String

Язык Java обеспечивает специальную поддержку оператора конкатенации строк (+) и преобразования других объектов в строки. Конкатенация строк реализуется с помощью класса StringBuilder (или StringBuffer) и его метода добавления. Строковые преобразования реализуются через метод toString, определяемый Object и наследуемый всеми классами в Java. Для получения дополнительной информации о конкатенации и преобразовании строк см. Гослинг, Джой и Стил, Спецификация языка Java.

Еще дальше - компилятор может использовать тот факт, что все они являются строковыми константами, и присоединяться к ним даже до выполнения ( JLS ссылки )

9 голосов
/ 25 марта 2011

Фиксированный литерал, как в вашем примере, более эффективен, чем использование StringBuilder.

Фиксированный литерал будет обнаружен компилятором и будет встроен как одно значение, поэтому две строки

String s = "one" + "two" + "three";

и

String s = "onetwothree";

сгенерируют точнотот же байт-код.

Изображение отличается, хотя, если конкатенация выполняется не с литералами, а с вызовами функций.

Когда вам нужно динамически добавлять строки, предпочтите StringBuilder, а не StringBuffer, поскольку он немногобыстрее как то не синхронизируется.

Вот пример байт-кода:

public class Test
{
   private String s = "one" + "two" + "three";
}

public class Test2
{
   private String s2 = "onetwothree";
}

сгенерированный байт-код для этих классов:

c:\Temp>javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   aload_0
   5:   ldc     #2; //String onetwothree
   7:   putfield        #3; //Field s:Ljava/lang/String;
   10:  return
}
c:\Temp>javap -c Test2
Compiled from "Test2.java"
public class Test2 extends java.lang.Object{
public Test2();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   aload_0
   5:   ldc     #2; //String onetwothree
   7:   putfield        #3; //Field s:Ljava/lang/String;
   10:  return
}

Как видите, обе переменные обрабатываются одинаково.

Я не думаю, что это относится к языковой спецификации, поскольку это «просто» оптимизация компилятора.

Другой компилятор (я использовал компилятор Sun) может делать что-то совершенно другое - это нормально, пока поведение не меняется.

4 голосов
/ 25 марта 2011

На самом деле компилятор уже применяет эту оптимизацию для вас в последних версиях Java (по крайней мере, с версии 1.5, я думаю).

Что происходит, когда компилятор Java видит много конкатенаций строк в одной строке?

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.18.1.2

0 голосов
/ 25 марта 2011

Просто постоянное соединение строк оптимизируется во время компиляции и является тривиальным.Проблема в том, что вы делаете что-то менее тривиальное:

String example1 = "Prefix" + variableString1 + "Suffix";

наихудший случай - циклы с добавлением, где каждая итерация должна создавать новуюстрока.Так как это является обычным для буферизованного чтения файлов, вы можете получить очень большие строки при воссоздании, проблема, с которой я недавно столкнулся.

Хотя я понимаю, почему вы хотите делать то, что делаете, структуры кода слишком разные, чтобы их можно было просто вставить и заменить, и сценарий для редактирования кода должен быть достаточно продвинутым, чтобыв состоянии справиться со всеми ссылками.Может быть, есть способ с аннонимными внутренними классами, хотя это может позволить вам сохранить ту же самую строковую ссылку, но обернуть фактическую конструкцию в строителях строк.Это, вероятно, ничем не отличается от того, что оптимизатор уже делает, хотя

...