Вопрос: Как оптимизировать код Java при работе со строчками?

Лучший ответ: да, использовать StringBuilder

Худший ответ: Про кеширование
Если у вас condition бОльшую часть времени имеет малый набор возможных значений, то кешированием в данном случае будет создание хешмапы, где ключ - condition, значение - condition + ",". Можете даже использовать какой-нибудь LRU-кеш, что бы редко используемые ключи постепенно удалялись из кеша и не занимали память.

Но если честно, в данном случае операция condition + "," настолько незначительна по вычислительной сложности, что хоть какое-то изменение вы заметите только если у вас этот участок кода вызывается в горячем цикле и генерирует столько мусора, что паузы GC перевешивают дополнительные вычисления хеша, ветвления и добавление новых данных в кеш. Но даже в этом случае нужно профилировать, например с помощью JMH и VisualVM.

Теперь по поводу StringBuilder.
Сразу скажу, что у меня нет под рукой IDE для Java, что бы проверить то, что будет написано дальше, все выводы сделаны только глядя на исходный код классов String и StringBuilder. Итак, поехали:

 Код condition + "," будет преобразован компилятором в new StringBuilder().append(condition).append(",").toString() Это сразу +2 созданных объекта: StringBuilder и новый String, который будет создан в результате вызова метода StringBuilder.toString()

a = a.replace("^Var1:", newString); внутри себя тоже создаёт StringBuilder, у которого потом вызывается метод toString() - еще +2 объекта

a = a + System.lineSeparator(); опять же будет преобразован в StringBuilder + toString()


Итого, у вас создаётся минимум 6 объектов.

Если переменная condition может иметь произвольное значение (т.е. операции с ней нет смысла кешировать, так как всё-равно придётся каждый раз вычислять новое значение), то можете попробовать воспользоваться методом condition.concat(String str) - будете создавать только 1 объект вместо 2. Будет ли это быстрее? Не знаю, надо профилировать.
Далее, после входа в блок if создаём новый StringBuilder вместимостью a.length() + condition.length() + 2. Если не указать длину строки, то вместимость у StringBuilder будет либо 16 символов, либо равной длине значения в переменной a (в зависимости от того, какой конструктор будет использован). И при конкатенации с новыми строками скорее всего возникнет необходимость увеличивать размер буфера, что приведёт к дополнительному копированию массивов (создать буфер с новым размером, скопировать содержимое старого буфера в новый). Поэтому желательно сразу рассчитать правильную длину результирующей строки. В любом случае, это тоже +1 объект.
a.replace(CharSequence target, CharSequence replacement) можно заменить методом StringBuilder.replace(int start, int end, String str) (придётся вручную вычислить начало и конец подстроки, которую вы хотите заменить).
Вместо a = a + System.lineSeparator(); используйте a.append(System.lineSeparator()).
out.append(a); приведёт к созданию еще 1 объекта - либо вы вручную вызовете a.toString(), либо этот метод будет вызван за вас в методе out.append(CharSequence seq). И скорее всего приведёт еще и к копированию массива символов внутри переменной out, если вы заранее не указали вместимость с запасом.

Итого, 3 объекта против изначальных 6 с несколькими не сразу очевидными НО. Стоит ли усложнение кода полученной экономии? Не уверен, надо профилировать. Ну и учтите, что производительность самого StringBuilder может быть разной, в зависимости от того, как вы его используете.

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