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

StackOverflow https://stackoverflow.com/questions/124148

  •  02-07-2019
  •  | 
  •  

Вопрос

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

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

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

Integer i = null;

Теперь проверка на равенство завершается неудачей.

Хорошая ли практика Java всегда использовать примитивные классы-оболочки?Очевидно, что это устранило бы некоторые ошибки на раннем этапе, но каковы у этого недостатки?Влияет ли это на производительность или объем памяти приложения?Есть ли какие-нибудь подлые подводные камни?

Это было полезно?

Решение

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

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

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

Хитрый попался? i.equals(j) когда я есть null.

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

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

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

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

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

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

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

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

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

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

if( i == 10 )

будет работать, как и раньше, но

if( i == 128 )

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

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

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

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

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

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

Не переключайтесь на непримитивы только для того, чтобы получить это средство.Используйте логическое значение, чтобы указать, было ли задано значение или нет.Если вам не нравится это решение, и вы знаете, что ваши целые числа будут находиться в некотором разумном пределе (или вас не волнует случайный сбой), используйте определенное значение для указания "неинициализированный", например Integer .МИНИМАЛЬНОЕ ЗНАЧЕНИЕ.Но это гораздо менее безопасное решение, чем логическое.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top