Зачем вам нужны беззнаковые типы в Java?

Я часто слышал жалобы на Java за отсутствие неподписанных типов данных. См., например, этот комментарий. Я хотел бы знать, как это проблема? Я программирую на Java около 10 лет, и у меня никогда не было с этим проблем. Иногда при преобразовании байтов в целые числа требуется & 0xFF, но я не считаю это проблемой.

Поскольку числа без знака и со знаком представлены одними и теми же битовыми значениями, единственные места, о которых я могу думать, где важна подпись, это:

  • При преобразовании чисел в другое битовое представление. Между 8-, 16- и 32-битными целыми типами вы можете использовать битовые маски, если это необходимо.
  • При преобразовании чисел в десятичный формат, обычно в строки.
  • Взаимодействие с системами, отличными от Java, через API или протоколы. Опять же, данные просто биты, поэтому я не вижу здесь проблемы.
  • Использование чисел в качестве памяти или других смещений. С 32-битными целыми это может быть проблемой для очень больших смещений.

Вместо этого мне проще, что мне не нужно рассматривать операции между беззнаковыми и подписанными числами и преобразования между ними. Что мне не хватает? Каковы реальные преимущества наличия неподписанных типов в языке программирования и как они сделают Java лучше?


person msell    schedule 05.04.2012    source источник
comment
К вашему сведению: /, %, < и > имеют разные интерпретации для значений со знаком и без знака.   -  person Louis Wasserman    schedule 05.04.2012


Ответы (3)


Иногда при преобразовании байтов в целые числа требуется & 0xFF, но я не считаю это проблемой.

Почему нет? Является ли «применение побитового И с 0xFF» частью того, что пытается представить ваш код? Если нет, то почему это должно быть частью того, что вы написали? На самом деле я обнаружил, что почти все, что я хочу сделать с байтами, кроме простого копирования их из одного места в другое, требует маски. Я хочу, чтобы мой код не содержал мусора; этому мешает отсутствие беззнаковых байтов :(

Кроме того, рассмотрите API, который всегда возвращает неотрицательное значение или только принимает неотрицательные значения. Использование беззнакового типа позволяет вам выразить это ясно, без необходимости проверки. Лично я считаю позором, что неподписанные типы не используются больше в .NET, например. для таких вещей, как String.Length, ICollection.Count и т. д. Очень часто значение, естественно, может быть только неотрицательным.

Является ли отсутствие беззнаковых типов в Java фатальным недостатком? Явно нет. Это раздражает? Абсолютно.

Комментарий, который вы цитируете, бьет в самую точку:

Отсутствие в Java неподписанных типов данных также противоречит этому. Да, вы можете обойти это, но это не идеально, и вы будете использовать код, который на самом деле неправильно отражает базовые данные.

Предположим, вы взаимодействуете с другой системой, которой требуется 16-битное целое число без знака, и вы хотите представить число 65535. Вы утверждаете, что «данные — это просто биты, поэтому я не вижу здесь проблемы». " - но необходимость передать -1 для обозначения 65535 является проблемой. Любое несоответствие импеданса между представлением ваших данных и их основным значением вносит дополнительный скачок скорости при написании, чтении и тестировании кода.

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

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

// This should be considered unsigned - so a value of -1 is "really" 65535
short length = /* some value */;
// This is really signed
short foo = /* some value */;

boolean result = foo < length;

Предположим, что foo равно 100, а length равно -1. Каков логический результат? Значение length представляет 65 535, поэтому логически foo меньше его. Но вы, вероятно, согласитесь с приведенным выше кодом и получите неправильный результат.

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

Вы также можете прочитать это интервью с Джошуа Блохом (кэш Google, насколько я полагаю, его больше нет на java.sun.com), в том числе:

О, хороший вопрос... Я хочу сказать, что самое странное в платформе Java — это то, что тип байта подписан. Я никогда не слышал объяснения этому. Это довольно нелогично и вызывает всевозможные ошибки.

person Jon Skeet    schedule 05.04.2012
comment
Если это поможет, Guava был добавление некоторой поддержки обработки значений как беззнаковых. - person Louis Wasserman; 05.04.2012
comment
@LouisWasserman: Это, безусловно, помогает, но это обходной путь по сравнению с тем, что на языке :( - person Jon Skeet; 05.04.2012
comment
Вместо -1 я просто пишу (коротко) 65535, небольшое раздражение. - person msell; 06.04.2012
comment
С беззнаковыми индексами массива обратные циклы for являются злом. for (uint i = array.length - 1; i ›= 0; i--) напрямую не работает. Это раздражало меня больше, чем битмаски. - person msell; 06.04.2012
comment
Спасибо за ответ. Хорошо объясняет проблемы. Тем не менее, я не думаю, что какие-либо из этих проблем так уж плохи. Как вы сами сказали, они раздражают. Я по-прежнему не хотел бы, чтобы в Java добавлялись неподписанные типы, поскольку их отсутствие ничего не ограничивает, а только усложняет выражение некоторых вещей. Меня больше раздражает в C, когда нужно преобразовать между неподписанным и подписанным, так как это происходит довольно часто. Например, вычитание двух значений без знака или ограничение индексов массива значениями без знака, но затем необходимо пометить недопустимый индекс значением -1. - person msell; 06.04.2012
comment
@msell: Может быть, у нас тоже не должно быть long. В конце концов, вы можете сделать все это, используя два значения int. Черт возьми, зачем возиться с чем-то другим, кроме одного типа bit? Если вам нужно более одного бита, используйте их массив. Это будет только раздражение, верно? Я думаю, что, вероятно, слишком поздно добавлять неподписанные типы в Java сейчас, так как множество естественных способов их использования уже существует с подписанными типами. Но мне все равно жаль, что их там нет. Я очень твердо верю, что чем точнее вы сможете представить исходные данные в системе типов, тем чище будет ваш код. - person Jon Skeet; 06.04.2012

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

Целочисленный тип без знака хранит вдвое больше неотрицательных значений в том же пространстве, что и соответствующий целочисленный тип со знаком. Поэтому, если вы хотите использовать в Java любые данные, обычно используемые в языке с беззнаковыми значениями, такие как значение даты POSIX (количество секунд без знака), которое обычно используется с C, то, как правило, вам нужно будет использовать более широкий целочисленный тип чем C будет использовать. Если вы обрабатываете много таких значений, вы снова потратите как место для хранения, так и время выборки-выполнения.

person minopret    schedule 05.04.2012

Времена, когда я использовал типы данных без знака, были, когда я читал большие блоки данных, которые соответствуют изображениям, или работал с openGL. Я лично предпочитаю unsigned, если знаю, что что-то никогда не будет отрицательным, как своего рода «функция безопасности».

Типы без знака полезны для побитового сравнения, и я почти уверен, что они широко используются в графике.

person Oofpez    schedule 05.04.2012