Почему строки неизменны во многих языках программирования?

Возможный дубликат:
Почему строки не могут быть изменены в Java и .NET?
Почему .NET String является неизменной?

Для этого выбраны несколько языков, таких как С#, Java и Python. Если он предназначен для экономии памяти или повышения эффективности для операций, таких как сравнение, какой эффект он оказывает на конкатенацию и другие операции модификации?

Ответ 1

Неизменяемые типы обычно хороши:

  • Они работают лучше для concurrency (вам не нужно блокировать что-то, что не может измениться!)
  • Они уменьшают ошибки: изменяемые объекты уязвимы для изменения, если вы не ожидаете, что это может привести к появлению всех видов странных ошибок ( "действие на расстоянии" )
  • Их можно безопасно разделить (т.е. несколько ссылок на один и тот же объект), что может сократить потребление памяти и улучшить использование кеша.
  • Совместное использование также делает копирование очень дешевой операции O (1), когда это будет O (n), если вам нужно взять защитную копию изменяемого объекта. Это очень важно, потому что копирование является невероятно распространенной операцией (например, когда вы хотите передавать параметры вокруг....)

В результате это довольно разумный выбор языка, чтобы сделать строки неизменяемыми.

Некоторые языки (особенно функциональные языки, такие как Haskell и Clojure) идут еще дальше и делают практически все неизменным. Это просветительское видео очень стоит посмотреть, если вы заинтересованы в преимуществах неизменности.

Есть несколько незначительных недостатков для неизменяемых типов:

  • Операции, которые создают измененную строку, такую ​​как конкатенация, дороже, потому что вам нужно создавать новые объекты. Обычно стоимость O (n + m) для конкатенации двух неизменяемых строк, хотя она может достигать O (log (m + n)), если вы используете структуру данных на основе дерева, такую ​​как Rope. Кроме того, вы всегда можете использовать специальные инструменты, такие как Java StringBuilder, если вам действительно нужно эффективно конкатенировать строки.
  • Небольшое изменение в большой строке может привести к необходимости создания полностью новой копии большой строки, что, очевидно, увеличивает потребление памяти. Обратите внимание, однако, что это обычно не является большой проблемой в сборках мусора, поскольку старая копия будет получать мусор, собранный довольно быстро, если вы не будете ссылаться на него.

В целом, однако, преимущества неизменности значительно перевешивают незначительные недостатки. Даже если вас интересует только производительность, преимущества concurrency и дешевизна копирования в целом сделают неизменяемые строки намного более эффективными, чем изменчивые с блокировкой и защитным копированием.

Ответ 2

В основном он предназначен для предотвращения ошибок программирования. Например, строки часто используются как ключи в хэш-таблицах. Если они могут измениться, хеш-таблица испортится. И это только один пример, когда изменение части данных при использовании, вызывает проблемы. Безопасность - это другое: если вы проверяете, разрешен ли пользователю доступ к файлу по заданному пути, прежде чем выполнять запрошенную им операцию, строка, содержащая путь, не будет изменяться...

Это становится еще более важным, когда вы выполняете многопоточность. Неизменяемые данные могут быть безопасно переданы между потоками, в то время как изменяемые данные приводят к бесконечным головным болям.

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

Ответ 3

В Java не только String, но и все примитивные классы Wrapper (Integer, Double, Character и т.д.) являются неизменяемыми. Я не уверен в конкретной причине, но я думаю, что это основные типы данных, на которых работают все схемы программирования. Если они меняются, все может разразиться. Чтобы быть более конкретным, я буду использовать пример: скажем, вы открыли соединение сокета с удаленным хостом. Имя хоста будет String, а порт будет Integer. Что делать, если эти значения изменяются после установления соединения.

Что касается производительности, Java выделяет память этим классам из отдельного раздела памяти, называемого Literal Pool, а не из стека или кучи. Литературный пул проиндексирован, и если вы дважды используете строку "String", они указывают на тот же объект из Literal пула.

Ответ 4

Наличие строк как неизменяемых также позволяет легко создавать новые ссылки на строки, так как те же/похожие строки будут легко доступны из пула ранее созданных строк. Тем самым снижается стоимость создания нового объекта.