На какой длине находится строковый ключ HashMap, который считается плохой практикой?

Я стараюсь постоянно следить за хорошей производительностью и чистым кодом.

У меня возникают трудности с попыткой понять, имеет ли смысл использовать HashMap с ключами из 150 символов.

  • Существует ли неписанный закон для длины ключа HashMap?
  • Считаете ли вы, что у плохой практики есть клавиши String, скажем 150 символов?
  • Это влияет на производительность? На какой длине?

Ответ 1

Не совсем, 150 символов Строка относительно тривиальна для вычисления hashCode для.

Если сказать, что в подобных обстоятельствах я бы посоветовал вам протестировать его!

Создайте процедуру, которая заполняет HashMap, скажем, вставляя здесь размер, который представляет собой случайные значения вашего сценария использования с 5 символьными строками в качестве ключей. Измерьте, сколько времени потребуется. Затем сделайте то же самое для 15 символов и посмотрите, как он масштабируется.

Кроме того, строки в Java неизменяемы, а это означает, что hashCode можно кэшировать для каждой строки, которая хранится в пуле констант String, и не нужно перечитывать, когда вы вызываете hashCode в том же объекте String.

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

Ответ 2

Существует ли неписанный закон для длины ключа HashMap?

Если есть, он также не подписан. Я бы измерил ваш случай использования в профилировщике и только беспокоился о вещах, которые вы можете измерить как о проблеме, а не о том, что вы можете себе представить, может быть проблемой.

Считается ли плохой практикой наличие клавиш String, допустим, 150 символов?

Я сомневаюсь.

Это влияет на производительность? На какой длине?

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


Существует экзотический случай, когда добавление строк с hashCode() от нуля - плохая идея. Это связано с тем, что в Java 1.0-6 не оптимизируется использование хэш-кода нуля, и его можно предсказать для атак типа "отказ в обслуживании". Java 7 исправляет это, имея вторичный, менее предсказуемый хэш-код.

Почему кеш-код hashCode() отсутствует? <?

Ответ 3

Длинный ответ: Быстрый просмотр исходного кода String::hashCode() показывает, что хэш кэшируется после первого вызова. Между тем, String::equals() - O (n), если строки равны, но не идентичны (т.е. equals() истинно, но == является ложным, потому что они распределены по разным адресам).

Таким образом, влияние на производительность вы увидите:

  • Передача никогда не хэшированных строк при вызовах функций HashMap. Однако генерация множества новых строк будет влиять на производительность сама по себе.

  • Вызов HashMap::get() и HashMap::put() с использованием строкового ключа, который равен ключу уже в HashMap (потому что если ключ отсутствует в коллекции, то скорее всего только hashCode() будет но если это так, equals() будет сравнивать все символы, пока не определит, что строки равны). Но только если строки, переданные этим функциям, не являются теми же объектами, которые уже находятся в HashMap, потому что в этом случае equals() выполняется очень быстро.

  • Кроме того, строковые литералы, строковые константы и строки вручную intern() 'd присоединяются к пулу констант String, в котором все "равные" строки являются одним и тем же объектом с тем же адресом. Поэтому, если работать исключительно с такими строками, hashCode и equals очень быстрые.

Конечно, влияние производительности не будет заметно, если вы не выполняете вышеупомянутые операции в узком цикле (потому что 150 символов не длинны, а hashCode() и equals() эффективны).

Короткий ответ: Тест.

Ответ 4

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

Итак, как долго длинные строки влияют на производительность хеш-таблицы?

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

  • Алгоритм hashcode для String использует все символы строки, и поэтому его стоимость пропорциональна длине строки. Это смягчается тем фактом, что хэш-коды String кэшируются. (Второе и последующее время, когда вы вызываете hashcode в String, вы получаете кешированное значение.) Однако это помогает (здесь), если вы выполняете несколько операций хэш-таблицы с одним и тем же объектом String в качестве ключа.

  • Когда вы получаете столкновение хэшей, хеш-таблица возвращается к использованию String.equals() для сравнения ключей при поиске выбранной хеш-цепи. В худшем случае (например, когда строки equal, но не ==), String.equals() включает в себя сравнение всех символов двух строк.

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