Почему конкатенация строк через плюс не рекомендуется, но проходит ревью и проверки качества кода?
Что проверяют
Отличаете ли вы реальную проблему от заученного правила. Конкатенация плюсом в одном выражении сегодня нормальна и часто быстрее ручного StringBuilder, дорогой она становится в цикле. Интервьюер проверяет, знаете ли вы, во что компилятор превращает плюс, и понимаете ли, почему статический анализ молчит.
Как отвечать
Строки неизменяемы, поэтому каждое объединение создаёт новый объект. Но одно выражение с плюсами компилятор собирает сам: современный javac вставляет вызов через invokedynamic, и строка собирается за один проход с точным расчётом размера буфера. Заменять такое выражение ручным StringBuilder смысла нет.
Проблема начинается там, где объединение выполняется многократно:
String s = "";
for (String part : parts) {
s += part; // новый объект и копирование накопленного на каждой итерации
}Здесь оптимизация невозможна: на каждой итерации выражение своё, и объём копирования растёт квадратично от длины результата. Правильные варианты: StringBuilder с заранее заданной ёмкостью, String.join, Collectors.joining.
Почему это проходит проверки: в подавляющем большинстве мест плюс безвреден, а анализаторы ловят только синтаксически очевидный случай, объединение прямо в теле цикла. Стоит упомянуть и логирование: log.debug("x=" + x) собирает строку даже при выключенном уровне, поэтому значения передают шаблоном с подстановкой.
Где спотыкаются
Говорят «плюс всегда медленный, всегда берите StringBuilder». Следом просят рассказать, как это компилируется, и ответа нет. Ручной билдер ради трёх кусков это лишний шум в коде без всякого выигрыша.
Второе: называют точный множитель ускорения по памяти. Разница зависит от числа итераций и длины строк, честнее говорить про сложность и предлагать замер на JMH: цикл с секундомером покажет прогрев виртуальной машины, а не работу со строками.
Третье: берут StringBuffer «на всякий случай». Синхронизация стоит денег и всё равно не делает серию добавлений атомарной. Ещё частый случай: объединение спрятано в методе, который зовут из цикла, и анализатор его не видит.