Инициализация StringBuilder для использования кодера UTF-16

Рассмотрим следующий код в Java 11:

StringBuilder sb = new StringBuilder("one");
sb.append("δύο");  // "two"

Первая строка создает StringBuilder, который использует кодировщик Latin1 (один байт на символ). Затем вторая строка заставляет StringBuilder понять, что вместо этого ему нужно использовать кодировщик UTF16, поэтому он копирует свое текущее содержимое в новый массив перед добавлением новых символов UTF-16.

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

Есть ли способ создать экземпляр StringBuilder, который с самого начала использует UTF16?

альтернатива в одну сторону sb.append(new String("δύο","UTF-16"))

Akash Shah 30.05.2019 12:45
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
1
409
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Кажется, что очевидного нет. Если вы хотите повлиять на способ инициализации StringBuffer, я бы предложил создать утилиту «инициализатор», которая реализует CharSequence и использовать соответствующий конструктор StringBuilder. Вы можете передать любую длину и содержание char, которое вы пожелаете, и внутренности StringBuilder должны быть достаточно умными, чтобы уловить это.

Однако, глядя на реализацию OpenJDK 11, кажется, что он одержим тем, чтобы начать с Latin1, несмотря ни на что. Некоторая форма перераспределения, кажется, происходит всегда.

Спасибо - интересная информация.

DodgyCodeException 30.05.2019 14:55
Ответ принят как подходящий

В версии StringBuilder для Java 11 или Java 12 нет ничего, что могло бы сделать это.

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

Если это будет иметь существенное значение, вы можете реализовать свою собственную версию StringBuilder (расширив те же интерфейсы для совместимости).

В качестве альтернативы, если вы готовы ждать, вы можете загрузить исходный код OpenJDK и разработать / собрать / протестировать расширение для StringBuilder ... и представить его как патч для рассмотрения. (Если вы включили тесты, которые продемонстрировали явное преимущество в производительности, это увеличило бы шансы на включение.)

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

Marcono1234 03.11.2019 00:25

Проведя немного больше исследований по этому вопросу, я даю еще один ответ на свой вопрос (переполнение стека говорит, что вполне приемлемо ответить на ваш собственный вопрос).

Как Славомир говорит, StringBuilder инициализируется с помощью Latin1, несмотря ни на что. Предположим, вы в основном пишете на таком языке, как русский, китайский, хинди или греческий. Вы хотите построить строку, максимальный размер которой вам уже известен, поэтому вы используете аргумент начальной емкости:

StringBuilder sb = new StringBuilder(4096);
sb.append("Здравствуйте!");  // Should easily fit in 4 kilobytes, right?

Тем не менее, приведенный выше вызов append отбрасывает буфер размером 4 КБ, который вы ранее инициализировали, и выделяет новый буфер. Вы построили StringBuilder с начальной емкостью, чтобы избежать перераспределения буфера, но StringBuilder все равно перераспределил его. И он перераспределил его, хотя он уже был достаточно большим!

Обходной путь — запустить java с помощью опции JVM -XX:-CompactStrings.

Если вы постоянно используете один из этих языков, ваши строки все равно будут использовать UTF-16, поэтому отключение сжатия строк при запуске уменьшит накладные расходы на проверку каждой предоставленной вами строки, чтобы увидеть, можно ли ее сохранить с использованием кодировки Latin1.

См. также Выступление Хайнца Кабуца на jPrime Bulgaria, 29 мая 2019 г., где он заставляет StringBuilder исчерпать память из-за этой «функции».

Другие вопросы по теме