Строковая сборка по StringBuilder vs StringWriter и PrintWriter - программирование
Подтвердить что ты не робот

Строковая сборка по StringBuilder vs StringWriter и PrintWriter

Недавно я столкнулся с идиомой, которую я раньше не видел: сборка строк по StringWriter и PrintWriter. Я имею в виду, я знаю, как их использовать, но я всегда использовал StringBuilder. Есть ли конкретная причина для предпочтения одного над другим? Метод StringBuilder кажется мне более естественным, но это просто стиль?

Я рассмотрел несколько вопросов здесь (в том числе тот, который наиболее близок: StringWriter или StringBuilder), но ни один, в котором ответы фактически не затрагивают вопрос о том, есть причина предпочесть один за другим для простой сборки строк.

Это идиома, которую я видел и использовал много раз: строковая сборка по StringBuilder:


    public static String newline = System.getProperty("line.separator");
    public String viaStringBuilder () {
       StringBuilder builder = new StringBuilder();
       builder.append("first thing").append(newline);  // NOTE: avoid doing builder.append("first thing" + newline);
       builder.append("second thing").append(newline);
       // ... several things
       builder.append("last thing").append(newline);
       return builder.toString();
    }

И это новая идиома: сборка строк по StringWriter и PrintWriter:


    public String viaWriters() {
       StringWriter stringWriter = new StringWriter();
       PrintWriter printWriter = new PrintWriter(stringWriter);
       printWriter.println("first thing");
       printWriter.println("second thing");
       // ... several things
       printWriter.println("last thing");
       printWriter.flush();
       printWriter.close();
       return stringWriter.toString();
    }

Изменить Похоже, что нет никакой конкретной причины предпочесть друг другу, поэтому я принял ответ, который наилучшим образом соответствует моему пониманию, и + 1 все остальные ответы. Кроме того, я отправил свой ответ, представив результаты сравнительного теста, который я выполнил, в ответ на один из ответов. Спасибо всем.

Изменить снова Оказывается, есть конкретная причина предпочесть один (в частности, StringBuilder) над другим. То, что я пропустил в первый раз, было добавлением новой строки. Когда вы добавляете новую строку (как указано выше, как отдельную добавку), она немного быстрее - не очень, но в сочетании с ясностью намерения, это определенно лучше. См. Мой ответ ниже для улучшения таймингов.

4b9b3361

Ответ 1

Стилистически подход StringBuilder является более чистым. Это меньше строк кода и использует класс, специально предназначенный для создания строк.

Другое соображение является более эффективным. Лучшим способом ответить на этот вопрос было бы сравнение двух альтернатив. Но есть некоторые четкие указатели, что StringBuilder должен быть быстрее. Для начала StringWriter использует StringBuilder StringBuffer под капотом для хранения символов, записанных в "поток".

Ответ 2

StringWriter - это то, что вы используете, когда хотите писать в строку, но вы работаете с API, который ожидает Writer или Stream. Это не альтернатива, это компромисс: вы используете StringWriter только тогда, когда вам нужно.

Ответ 3

Хорошо, поскольку ответы, похоже, подчеркивают стилистические причины предпочтения друг друга, я решил обобщить тест времени.

Изменить. Следуя приведенному выше замечанию robinst, теперь у меня есть три метода: один, который добавляет стиль PrintWriter (StringWriter), и два, которые используют StringBuilder: один с добавлением новой строки внутри добавления (как в оригинале: builder.append(thing + newline);), а другой - отдельное приложение (как указано выше: builder.append(thing).append(newline);).

Я следовал своей обычной схеме бенчмаркинга: сначала вызовите несколько методов (1000 в этом случае), чтобы дать время оптимизатора разогреться, а затем вызовите их много раз (100 000 в этом случае) в чередующейся последовательности, поэтому что любые изменения среды выполнения рабочей станции более справедливо распределены и запускают сам тест несколько раз и усредняют результаты.

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

Код для этого здесь: http://pastebin.com/vtZFzuds

Примечание. Я еще не обновил код pastebin, чтобы отразить новый тест.

TL, DR? Средние результаты для 100 000 вызовов для каждого метода довольно близки:

  • 0.11908 мс за вызов с использованием StringBuilder (+ новая строка внутри патента)
  • 0.10201 мс за вызов с использованием StringBuilder (новая строка как отдельная добавка)
  • 0.10803 мс за вызов с использованием PrintWriter (StringWriter)

Это настолько близко, что время для меня почти не имеет значения, поэтому я буду продолжать делать то, что я всегда делал: StringBuilder (с отдельным дополнением) по стилистическим соображениям. Конечно, работая в этой установленной и зрелой кодовой базе, я в основном придерживаюсь существующих соглашений, чтобы свести к минимуму неожиданность.

Ответ 4

Писатели - PrintWriter записывает в поток. Это странные вещи, такие как подавление IOExceptions. System.out - один из них. - StringWriter - это Writer, который записывает в StringBuffer (аналогично ByteArrayOutputStream для OutputStreams)

StringBuilder - и, конечно, StringBuilder - это то, что вам нужно, если вы просто хотите построить строки в памяти.

Заключение

Писатели по дизайну предназначены для того, чтобы выталкивать персональные данные из потока (обычно в файл или через соединение), поэтому возможность использования Writers для простой сборки строк кажется немного побочным эффектом.

StringBuilder (и его синхронизированный sibling StringBuffer) предназначены для сборки строк (чтение строк). Если вы посмотрите на StringBuilder API, вы можете увидеть, что вы можете делать только добавление ванили, но также заменять, реверсировать, вставлять и т.д. StringBuilder - это ваша строковая конструкция друг.

Ответ 5

Я вижу два преимущества метода PrintWriter: (1) Вам не нужно добавлять "+ новую строку" в конце каждой отдельной строки, что на самом деле приводит к сокращению кода, если вам нужно много писать. (2) Вам не нужно вызывать System.getProperty(); вы позволяете PrintWriter беспокоиться о том, что должно быть символом новой строки.

Ответ 6

в этой ссылке: http://nohack.eingenetzt.com/java/java-stringwriter-vs-stringbuilder автор показывает, что StringWriter даже немного быстрее, чем StringBuilder.and также сказал: "Поэтому, когда большие объемы данных вступают в игру, StringWriter четко показывает свое превосходство в производительности по сравнению с StringBuilder".