Класс String создает неизменяемые строки. Это означает, что если применить любую операцию к строке или операции к строке, то в результате будет построена новая строка. Если эту новую строку не присвоить никакой переменной, то результат операции будет утерян. Соответственно операции над такими строками обязательно приводят к созданию новой строки. А это дополнительные расходы памяти и времени процессора. Если операций над строкой достаточно много, то часто бывает эффективней воспользоваться динамическими строками, которые реализуются классом StringBuilder.
Рассмотрим код ниже:
String s = "Some text";
int count = 100;
for(int i = 0; i<100;i++){
   s+=i;
}
**********************
StringBuilder s = new StringBuilder(110);
int count = 100;
s.append("Some text");
for(int i = 0;i<count;i++){
s.append(i);
}
В приведенном коде рассматривается одна и та же задача. Когда мы к заданной строке добавляем 100 новых подстрок. В первом примере для этой цели используется класс String, что не очень эффективно, поскольку каждое добавление подстроки ведет к построению нового объекта String. А это дополнительный расход памяти и времени. Во втором примере эта задача решается с помощью класса StringBuilder. Мы заранее создаем объект класса StringBuilder, а затем с помощью метода append формируем нужную нам строку изменяя содержимое созданного объекта StringBuilder, но без пересоздания самого объекта.