Почему Java не поддерживает целые числа без знака? - PullRequest
357 голосов
/ 10 января 2009

Почему Java не поддерживает целые числа без знака?

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

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

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

В чем недостаток включения этих?

Ответы [ 15 ]

184 голосов
/ 10 января 2009

Это из интервью с Гослингом и другими , о простоте:

Гослинг: Для меня как для дизайнера языков, который я не считаю себя в наши дни тем, что на самом деле означало «простое», было то, могу ли я ожидать, что J. Random Developer будет держать спецификацию в своей голове. Это определение говорит о том, что, например, Java не является - и на самом деле многие из этих языков заканчиваются множеством угловых случаев, вещей, которые на самом деле никто не понимает. Опросите любого разработчика на C о unsigned, и довольно скоро вы обнаружите, что почти никто из разработчиков C не понимает, что происходит с unsigned, что такое беззнаковая арифметика. Такие вещи делали Си сложным. Языковая часть Java, я думаю, довольно проста. Библиотеки, которые вы должны искать.

50 голосов
/ 10 января 2009

Читая между строк, я думаю, что логика была что-то вроде этого:

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

В основном, я бы сказал, что это было разумное решение. Возможно, я бы имел:

  • сделал байт без знака или, по крайней мере, предоставил альтернативы со знаком / без знака, возможно, с другими именами, для этого одного типа данных (сделать его подписанным хорошо для согласованности, но когда вам когда-нибудь нужен подписанный байт?)
  • покончено с «коротким» (когда вы в последний раз использовали 16-битную арифметику со знаком?)

Тем не менее, с небольшим количеством хитрости, операции с беззнаковыми значениями до 32 бит не так уж плохи, и большинству людей не нужно 64-разрядное деление без знака или сравнение.

18 голосов
/ 28 июля 2011

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

byte - 8-разрядное целое число со знаком

short - 16-разрядное целое число со знаком

int - 32-разрядное целое число со знаком

long - 64-разрядное целое число со знаком

char - 16-разрядный символ (целое число без знака)

Хотя char не поддерживает unsigned арифметику, по сути ее можно рассматривать как unsigned целое число. Вам бы пришлось явным образом привести арифметические операции обратно в char, но он дает вам возможность указать unsigned чисел.

char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ? 
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;

Да, нет прямой поддержки целых чисел без знака (очевидно, мне не пришлось бы преобразовывать большинство моих операций обратно в char, если бы была прямая поддержка). Тем не менее, безусловно, существует неподписанный примитивный тип данных. Мне бы тоже хотелось увидеть неподписанный байт, но я думаю, что удвоение стоимости памяти и использование вместо char - жизнеспособный вариант.


Редактировать

В JDK8 появились новые API для Long и Integer, которые предоставляют вспомогательные методы при обработке значений long и int как значений без знака.

  • compareUnsigned
  • divideUnsigned
  • parseUnsignedInt
  • parseUnsignedLong
  • remainderUnsigned
  • toUnsignedLong
  • toUnsignedString

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

16 голосов
/ 12 октября 2009

В Java есть типы без знака или хотя бы один: char - это беззнаковое сокращение. Так что, что бы ни извинял Гослинг, на самом деле это просто его невежество, почему нет других неподписанных типов.

Также короткие типы: шорты все время используются для мультимедиа. Причина в том, что вы можете разместить 2 сэмпла в одном 32-битном беззнаковом коде и векторизовать множество операций. То же самое с 8-битными данными и беззнаковым байтом. Вы можете разместить 4 или 8 образцов в регистре для векторизации.

14 голосов
/ 10 января 2009

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

12 голосов
/ 10 января 2009

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

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

11 голосов
/ 10 января 2009

Я думаю, что с Java все в порядке, добавление unsigned усложнит ее без особой выгоды. Даже с упрощенной целочисленной моделью большинство программистов на Java не знают, как ведут себя базовые числовые типы - просто прочитайте книгу Java Puzzlers , чтобы узнать, какие неправильные представления вы можете иметь.

Что касается практического совета:

  • Если ваши значения имеют произвольный размер и не вписываются в int, используйте long. Если они не вписываются в long, используйте BigInteger.

  • Используйте меньшие типы только для массивов, когда вам нужно сэкономить место.

  • Если вам нужно ровно 64/32/16/8 бит, используйте long / int / short / byte и перестаньте беспокоиться о знаковом бите, кроме деления, сравнения, верно сдвиг и кастинг.

См. Также этот ответ о "переносе генератора случайных чисел с C на Java".

6 голосов
/ 30 января 2014

Я знаю, что этот пост слишком старый; однако для вашего интереса в Java 8 и более поздних версиях вы можете использовать тип данных int для представления 32-разрядного целого без знака, которое имеет минимальное значение 0 и максимальное значение 2 32 - 1. Используйте класс Integer для использования типа данных int в качестве целого числа без знака, и в класс Integer были добавлены статические методы, такие как compareUnsigned(), divideUnsigned() и т. Д., Для поддержки арифметических операций для целых чисел без знака.

6 голосов
/ 24 февраля 2013

С JDK8 он имеет некоторую поддержку для них.

Мы все еще можем увидеть полную поддержку неподписанных типов в Java, несмотря на озабоченность Гослинга.

4 голосов
/ 10 января 2009

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

...