Почему java.util.UUID совместим?

UUID в java реализует Comparable. Это кажется мне немного странным, поскольку почти во всех случаях UUID генерируются случайным образом (или десериализуются откуда-то, но все же они, вероятно, изначально были сгенерированы случайным образом).

Кажется, нет никакого смысла сравнивать их, если вы не генерируете их вручную с последовательно увеличивающимся LSB / MSB, что может иметь смысл, если вам просто нужен очень большой идентификационный номер (два long вместо одного простого long), но это единственное объяснение, которое я могу придумать.

А как насчет использования их в качестве настоящего идентификатора в сущности? Точно так же, как вы сравниваете 2 longs, видя, "больше ли" объект, чем другой, то же самое можно сделать и с UUID.

Lino 25.06.2018 22:15

да, это объяснение, которое я написал в сообщении, оно будет работать, только если вы вручную сгенерируете UUID с увеличенным lsb / msb. но это не основной вариант использования UUID

paranoidAndroid 25.06.2018 22:16

UUID включает дату, не так ли? Вы можете сравнивать на основании этого. Это поведение?

zero298 25.06.2018 22:16

Предположим, вы прочитали 2 значения из строки и вам нужно проверить их на равенство (возможно, в некоторых сложных объектах json или что-то подобное)?

Morfic 25.06.2018 22:17

нет, uuid - это всего лишь два long, составляющие очень большое число, не имеет ничего общего с датой

paranoidAndroid 25.06.2018 22:17

@Morfic, что равно () не сравнивать

paranoidAndroid 25.06.2018 22:17

Уверены ли вы? V1 и V2 оба кодируют дату: Версия 1 (дата, время и MAC-адрес)

zero298 25.06.2018 22:18

Глядя на IETF RFC 4211, есть раздел о лексическом порядке UUID: «Правила лексической эквивалентности: Считайте каждое поле UUID целым числом без знака, как показано в таблице в разделе Раздел 4.1.2. Затем, чтобы сравнить пару UUID. , арифметически сравнить соответствующие поля каждого UUID в порядке значимости и в соответствии с их типом данных. Два UUID равны тогда и только тогда, когда все соответствующие поля равны ».

Turing85 25.06.2018 22:18

@ Turing85 верно, но все же в обычном случае использования UUID нет смысла сравнивать их, только проверяйте, равны ли они. Мне не нужно знать, является ли uuid «больше» или «меньше», чем другой uuid. хотя по сути это числа

paranoidAndroid 25.06.2018 22:19

@paranoidAndroid - именно так это определяется в RFC. Я не вижу ничего плохого в реализации, реализующей определенный порядок. Будет ли и как он использоваться, зависит от пользователя.

Turing85 25.06.2018 22:20

@paranoidAndroid «Мне не нужно знать, является ли uuid« больше »или« меньше », чем другой uuid», тогда не вызывайте compareTo. Просто потому, что вы этого не хотите, не означает, что другие этого не делают, особенно если стандарт, в котором объявлены UUID, говорит, что они должны быть сопоставимы.

Andy Turner 25.06.2018 22:20

@AndyTurner правильно, я не использую его :) но просто интересно, почему разработчики JDK решили реализовать метод сравнения для чего-то, что редко сравнивается таким образом

paranoidAndroid 25.06.2018 22:21

@paranoidAndroid «редко» - очень субъективный термин. Ты нет (я не знаю), другие могут.

Andy Turner 25.06.2018 22:22

@paranoidAndroid снова, потому что RFC определяет его. Чтобы быть совместимым с RFC, необходимо определить определенный порядок.

Turing85 25.06.2018 22:23

@ Turing85 Я могу согласиться с этой причиной. Спасибо.

paranoidAndroid 25.06.2018 22:24
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
15
1 951
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Это имеет смысл, если вы используете его, то есть как идентификатор.

Или, если необходимо хранить объекты в древовидных структурах данных.

Это необходимо, например, чтобы поместить их в TreeMap / TreeSet. Наиболее актуальные цитаты из RFC:

UUIDs are of a fixed size (128 bits) which is reasonably small compared to other alternatives. This lends itself well to sorting, ordering, and hashing of all sorts, storing in databases, simple allocation, and ease of programming in general.

UUIDs, as defined in this document, can also be ordered lexicographically. For a pair of UUIDs, the first one follows the second if the most significant field in which the UUIDs differ is greater for the first UUID. The second precedes the first if the most significant field in which the UUIDs differ is greater for the second UUID.

Не обязательно, чтобы это был Comparable, может быть где-то заявлен Comparator<UUID>.

Andy Turner 25.06.2018 22:23

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

paranoidAndroid 25.06.2018 22:23

Потому что хэш-карты не всегда являются самым быстрым способом найти что-то, а более быстрые способы часто включают в себя отсортированные структуры данных (TreeMap используется просто как пример одного). Сортированный массив с двоичным поиском, B + -дерево (часто используется в базах данных) и т. д.

Alexey Romanov 25.06.2018 22:28

Он также имеет преимущества при использовании в качестве ключей в HashMap: «Обратите внимание, что использование многих ключей с одним и тем же hashCode () - верный способ замедлить производительность любой хеш-таблицы. Чтобы уменьшить влияние, когда ключи сопоставимы, этот класс может использовать порядок сравнения между ключами, чтобы помочь разорвать связи». Хотя коллизии хеш-кодов обычно не должны быть слишком частыми для UUID, потому что их реализация хэш-кода действительно дает разумное распределение, существует НАМНОГО больше возможных UUID, чем хеши "Integer.MAX_VALUE"

Hulk 26.06.2018 08:47

Обновлено: как отметил Turing85 в комментариях (а затем в полноценный ответ), класс Java java.util.UUID реализует RFC 4122. Этот RFC четко определяет порядок, поэтому для этого класса имеет смысл реализовать такой порядок, то есть путем реализации Comparable.

Тем не менее, даже если сортировка не обслуживает никакой «бизнес-логики», у нее есть много других преимуществ.

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

Во-вторых, сортировка чрезвычайно помогает избежать тупиковых ситуаций. Если вы всегда обновляете объекты (и принимаете необходимые для этого блокировки) в одном и том же порядке, вы устраняете множество ловушек, когда X ожидает блокировки Y, которая сама ожидает блокировки X.

И наконец - почему бы не сделать UUID сопоставимым? Добавленный байтовый код для реализации compareTo незначительно увеличивает размер класса. Если вы не используете его в качестве Comparable, вы вряд ли пострадаете от него, а реализация Comparable дает пользователю класса дополнительную гибкость в использовании его как такового.

вы бы не сделали свой идентификационный номер сопоставимым, не так ли? С моей точки зрения, это почти то же самое

paranoidAndroid 25.06.2018 22:26

@ Turing85, это хороший момент - отредактировано в моем ответе, спасибо.

Mureinik 25.06.2018 22:44
Ответ принят как подходящий

Некоторые версии UUID имеют значение, закодированное в их значениях:

There are four different basic types of UUIDs: time-based, DCE security, name-based, and randomly generated UUIDs.

Из-за этого может иметь смысл сравнить UUID, поскольку вы можете получить значение из их значений. Вы можете свободно сказать: «Этот UUID был создан раньше или позже», чем другой.

Рассмотрим версии, определенные на Википедия:

  • Версия 1 (дата, время и MAC-адрес)
  • Версия 2 (дата, время и MAC-адрес, версия безопасности DCE)
  • Версии 3 и 5 (на основе имен пространств имен)
  • Версия 4 (случайная)

Вы даже можете увидеть это в JavaDoc:

The layout of a variant 2 (Leach-Salz) UUID is as follows: The most significant long consists of the following unsigned fields:

 0xFFFFFFFF00000000 time_low
 0x00000000FFFF0000 time_mid
 0x000000000000F000 version
 0x0000000000000FFF time_hi

См. Как создается UUID / GUID на основе времени

Приятно это знать. Я пометил как ответ. Спасибо

paranoidAndroid 25.06.2018 22:28

Хотя это правда, что «Вы могли бы свободно сказать:« Этот UUID был создан раньше или позже », чем другой», порядок, определенный RFC и реализацией Comparable, этого не делает, и именно этот макет объясняет, почему. Или вам нужно довольно расплывчатое определение слова «свободно» :) time_mid перекатывается и делает порядок отличным от временного для каждого 0xffffffff * 100 nanoseconds = 7.15827883 minutes.

Alexey Romanov 25.06.2018 23:10

@AlexeyRomanov, честно говоря, я не уверен, насколько я уверен в этом ответе. Казалось, что OP хотел конкретную причину, по которой вы могли сравнить UUID, и тот факт, что они могли гипотетически быть «отсортированными по дате», казался подходящим. Не знаю, согласен ли я с принятым ответом.

zero298 26.06.2018 00:55

Глядя на Javadoc из UUID, мы видим, что он ссылается на IETF RFC 4122: пространство имен URN универсального уникального идентификатора (UUID). В упомянутом RFC мы находим раздел, посвященный лексической эквивалентности:

Rules for Lexical Equivalence:
   Consider each field of the UUID to be an unsigned integer as shown
   in the table in section Section 4.1.2.  Then, to compare a pair of
   UUIDs, arithmetically compare the corresponding fields from each
   UUID in order of significance and according to their data type.
   Two UUIDs are equal if and only if all the corresponding fields
   are equal.

   [...]

   UUIDs, as defined in this document, can also be ordered
   lexicographically.  For a pair of UUIDs, the first one follows the
   second if the most significant field in which the UUIDs differ is
   greater for the first UUID.  The second precedes the first if the
   most significant field in which the UUIDs differ is greater for
   the second UUID.

Это означает: чтобы полностью реализовать упомянутый RFC, необходимо реализовать определенный порядок. Реализовать это в Java можно либо с помощью implements Comparable<...>, либо с помощью Comparator<...>. Поскольку порядок, определенный в RFC, является «естественным порядком» UUID, логично разрешить UUID implements Comparable<UUID>.

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


Адендум

Если кто-то проголосует за мой ответ, он должен также проголосовать за Ответ алексея. Мой ответ был написан позже, но он следует той же аргументации. Кроме того, Алексей приводит пример того, как этот заказ может быть полезен.

«На данный момент ни один из ответов, похоже, не подхватил этот комментарий» На самом деле мой ответил :) Это то, что относится к «более актуальным», поскольку этот абзац сам по себе только определяет, как должен себя вести equals.

Alexey Romanov 25.06.2018 22:53

Ха, смешно. Извините, почему-то не уловил. Однако первая часть моего ответа в любом случае устарела (и я уже отредактировал ее), так как Мурейник тоже уловил мой комментарий.

Turing85 25.06.2018 22:55

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