Подтвердить что ты не робот

Должен ли я больше никогда не использовать примитивные типы?

Смешение использования примитивных типов данных и их соответствующих классов-оболочек в Java может привести к множеству ошибок. Следующий пример иллюстрирует проблему:

int i = 4;
...
if (i == 10)
  doStuff();

Позже вы увидите, что вы хотите, чтобы переменная я была либо определена, либо undefined, поэтому вы изменяете описанную выше процедуру:

Integer i = null;

Теперь проверка равенства не выполняется.

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

4b9b3361

Ответ 1

Использование типов в коробке имеет проблемы с производительностью и памятью.

При выполнении сравнений (например, (i == 10)) java должен отключить тип перед выполнением сравнения. Даже при использовании i.equals(TEN) используется вызов метода, который является более дорогостоящим и (IMO) более уродливым, чем синтаксис ==.

Re memory, объект должен быть сохранен в куче (что также влияет на производительность), а также на сохранение самого значения.

Подкрадывается? i.equals(j), когда я null.

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

Ответ 2

Во-первых, переход от использования примитива к использованию объекта только для того, чтобы получить возможность установить его в null, вероятно, является плохим дизайнерским решением. У меня часто бывают аргументы с моими коллегами о том, является ли это нулевым значением или нет, и мое мнение, как правило, заключается в том, что оно не является (и, следовательно, не должно быть запрещено, поскольку значения дозорного значения должны быть), но в этом конкретном случае вы собираетесь из вашего пути, чтобы использовать его в качестве контрольной суммы. Пожалуйста, не надо. Создайте логическое значение, указывающее, действительно ли ваше целое, или создайте новый тип, который объединяет булево и целое число.

Обычно при использовании более новых версий Java я считаю, что мне не нужно явно создавать или применять к объектным версиям примитивов из-за поддержки автоматического бокса, которая была добавлена ​​некоторое время в 1.5 (возможно, сама по себе 1.5).

Ответ 3

Я бы предложил использовать примитивы все время, если у вас действительно нет понятия "null".

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

Для float/doubles вы можете рассматривать NaN как null, но помните, что NaN!= NaN, поэтому вам все еще нужны специальные проверки: Float.isNaN(x).

Было бы очень приятно, если бы были коллекции, которые поддерживали примитивные типы, вместо того, чтобы тратить время/накладные расходы на бокс.

Ответ 4

В вашем примере оператор if будет работать до тех пор, пока вы не перейдете на 127 (поскольку Integer autoboxing будет кэшировать значения до 127 и возвращать один и тот же экземпляр для каждого номера до этого значения)

Так что это хуже, чем вы его представляете...

if( i == 10 )

будет работать по-прежнему, но

if( i == 128 )

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

Ответ 5

Те типы java POD существуют по какой-то причине. Помимо накладных расходов, вы не можете выполнять обычные операции с объектами. Целое - это объект, который необходимо выделить и собрать мусор. Нет int.

Ответ 6

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

Есть две возможности: либо значение - это просто данные (код не будет действовать иначе, если он заполнен или нет), или это фактически указывает на то, что здесь есть два разных типа объекта (код действует по-разному если есть значение, отличное от нуля)

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

Если вы проверите нуль в какой-то момент, вы можете захотеть использовать подкласс, потому что, когда есть одна разница, обычно бывает больше. По крайней мере, вам нужен лучший способ указать вашу разницу, чем "если primitiveIntValue == null", это ничего не значит.

Ответ 7

Не переключайтесь на не-примитивы, чтобы получить это средство. Используйте boolean, чтобы указать, было ли задано значение или нет. Если вам не нравится это решение, и вы знаете, что ваши целые числа будут в некотором разумном пределе (или не заботятся о случайном сбое), используйте определенное значение, чтобы указать "неинициализированный", например Integer.MIN_VALUE. Но это гораздо менее безопасное решение, чем логическое.

Ответ 8

Когда вы добрались до этого "Позже", в ходе рефакторинга нужно было выполнить еще немного работы. Используйте примитивы, когда это возможно. (Период капитала) Затем создайте POJO, если потребуется больше функциональности. На мой взгляд, примитивные классы-оболочки лучше всего использовать для данных, которые необходимо перемещать по проводу, что означает сетевые приложения. Разрешение нулей в качестве допустимых значений вызывает головную боль, поскольку система "растет". К большому количеству кода, потраченному впустую или пропущенному, охраняя то, что должно быть простым сравнением.