@MishaXXL

В каком контексте значение класса String является неизменяемым в отличии от StringBuilder?

Почему нужно было помимо класса Stringсоздавать дополнительные классы по типу StringBuilder?

Из учебника.
Класс String аналогичен классу StringBuilder за исключением того, что он является неизменяемым.


1. По поводу изменения
В данном примере строка s спокойно изменяется путем конкатенации, что аналогично sb.append

2. Почему все методы StringBuilderнельзя было поместить в класс String, чтобы не плодить классы строк?

3. Почему s.equals(sb) равно false, если мы сравниваем только значения, а не ссылки
Значения у нас типа String, длина строк и символы одинаковые.

public class MyClass {
    public static void main(String args[]) {
        String s = "Hello";
        s += " Java!";
        
        String s2 = new String("Hello Java!");
        
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" Java!");
        
        System.out.println(s.equals(s2));
        System.out.println(s.equals(sb));
    }
}


Наткнулся на код из статьи и не понял для чего тут используют StringBuilderс append, а не просто Stringс конкатенацией, ведь после всё равно превращают его в String.
Для чего здесь эти манипуляции с классами String и почему здесь не обошлись без StringBuilder?
StringBuilder requestBuilder = new StringBuilder();
String line;
while (!(line = br.readLine()).isBlank()) {
   requestBuilder.append(line + "\r\n");
}
String request = requestBuilder.toString();
String[] requestsLines = request.split("\r\n");


Ссылка на статью
https://dev.to/mateuszjarzyna/build-your-own-http-...
  • Вопрос задан
  • 184 просмотра
Решения вопроса 5
xez
@xez Куратор тега Java
TL Junior Roo

Почему нужно было помимо класса String создавать дополнительные классы по типу StringBuilder?

Потому, что String - иммутабельный класс. Чтобы конструировать строки как раз добавлены StringBuffer (в версии 1.0) и StringBuilder (в 1.5).

В данном примере строка s спокойно изменяется путем конкатенации, что аналогично sb.append

В итоге у вас каждый раз создается новый объект. Не всегда это бывает уместно.

2. Почему все методы StringBuilderнельзя было поместить в класс String, чтобы не плодить классы строк?

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

3. Почему s.equals(sb) равно false, если мы сравниваем только значения, а не ссылки

Потому, что вы сравниваете разные объекты. StringBuilder - это не String.
Ответ написан
Комментировать
@Dementor
программист, архитектор, аналитик
1. Нет! Строки неизменяемые. Конкатенация строк - это операция по созданию нового объекта с новой ссылкой.

2. String это базовый тип для Java, а StringBuilder добавили только в 5-ю версию. Апгрейд существующего класса не стали делать по соображениям совместимости и чтобы не поломать String Pool, который для билдера не имеет смысла.

3. Потому что это разные типы!!! Хотите, чтобы String и StringBuilder сравнивались по содержимому? Делайте дочерние классы, в которых переопределяйте сравнение, а потом экземпляры своих классов присвойте переменным типов String и StringBuilder - магия, сравнение заработало!
Ответ написан
Комментировать
mayton2019
@mayton2019 Куратор тега Java
Bigdata Engineer
Почему все методы StringBuilderнельзя было поместить в класс String, чтобы не плодить классы строк?

Главный поинт при создании immutable String - безопасность кода. Когда компиллятор точно
знает что value строки не изменится - то он может доказать много кейсов и гарантировать что
разделяемая память не будет сломана. Особенно это важно для мультипоточки. Когда
разные потоки владеют строкой и здесь сам вопрос доказательства вдруг становится очень важным.

Язык С++ например такой защитой не обладает и для него строка как фундаментальный тип
может иногда мутировать. Тоесть если вы старались писать правильно то она конечно не мутирует.
Но в этом есть большая разница между C++ и Java. На уровне платформы гарантировано отсуствие
какого-то класса ошибок.

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

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

Immutable строки - это гениальное изобретение. Оно реализовано во многих языках и платформах
и оно практически спасает разработчика бизнес-приложений от трудно уловимых ошибок.
Ответ написан
sergey-gornostaev
@sergey-gornostaev Куратор тега Java
Седой и строгий
Во-первых, при конкатенации строк создаётся новая строка. Выполните в цикле миллион конкатенаций, получите миллион ненужных объектов, сожрете память, нагрузите сборщик мусора, программа начнёт тормозить, и ваш наниматель вас уволит. Во-вторых, строки - один из самых часто используемых классов в java-программах, поэтому очень важно, чтобы операции с ними были быстрыми, и именно неизменяемость строк позволила их очень сильно оптимизировать.

Послушайте, если осилите.
Ответ написан
@My1Name
Массив — структура данных хранящая набор значений, в простейшем случае фиксированой длины. Массивы не всегда удобно использовать, поэтому ряд языков программирования поддерживают динамические массивы и, Java один из таких языков. ⇨ Данные типа String - это массив char-ов в таких языках как Pascal, C, C++, Java и др.. В Java все строковые литералы помещаются в специальный объект (класс) под который выделяется память, а уже адрес этого объекта помещается в переменную, под которую тоже выделяется память. Java коллекции расширяют возможности работы с массивами и это пожалуй ответ на все ваши вопросы.
https://javarush.com/quests/lectures/questsyntaxpr...

Например, если вы заполните HashSet<String> то сможете проверить наличие определенного String-а в массиве строк, заменив s.equals(sb) на list.contains(sb) Такой код будет работать в оперативной памяти используя hashcode (32 битный идентификатор объекта). Это работает быстро и эффективно, так как числовые значения гораздо легче и быстрей сравнить. Однако, каждая строка будет представлять собой отдельный объект и занимать свою ячейку в памяти.

При конкатенации происходит приблизительно то же самое: Создаётся массив, где каждая строка - это отдельный объект (массив) разного размера. В момент конкатенации создаётся новый объект типа String с размером == сумма двух String и + 2 объекта "склеивания". А если у нас таких операций (итераций) много, то велика вероятность получить outofmemoryerror прежде чем GC (сборщик мусора) успеет собрать все созданные объекты.

В отличие от языков C/C++ в Java нет доступа к памяти. Программист не может удалить "cell memory" хранящую ссылку на объект и в этом нет необходимости. Эту работу выполняет Garbage collectors (GC) а вся работа с памятью происходит только через Java-машину (JVM).

С целью экономии памяти, начиная с версии JDK 5 для работы со String-ами в Java имеется StringBuilder. Таким образом у нас всегда один объект, который пропорционально заполненяет StringBuffer, подобно HashSet<String> но с одной ("резиновой") ячейкой в памяти.
https://docs.oracle.com/javase/8/docs/api/java/lan...
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы