Почему люди все еще используют примитивные типы в Java? - PullRequest
152 голосов
/ 05 марта 2011

Начиная с Java 5, у нас был бокс / распаковка примитивных типов, так что int оборачивается в java.lang.Integer, и так далее, и так далее.

В последнее время я вижу много новых Java-проектов (которым определенно требуется JRE по крайней мере версии 5, если не 6), которые используют int вместо java.lang.Integer, хотя это гораздо больше удобно использовать последний, так как он имеет несколько вспомогательных методов для преобразования в long значений и др.

Почему некоторые все еще используют примитивные типы в Java? Есть ли ощутимая выгода?

Ответы [ 20 ]

8 голосов
/ 18 июня 2014

Пара причин, чтобы не избавляться от примитивов:

  • Обратная совместимость.

Если ее устранить, любые старые программы даже не запустятся.

  • Перезапись JVM.

Вся JVM должна быть переписана для поддержки этой новой вещи.

  • Увеличенный объем памяти.

Вам необходимо сохранить значение и ссылку, которая использует больше памяти.Если у вас огромный массив байтов, использование byte значительно меньше, чем использование Byte.

  • Проблемы с нулевым указателем.

Объявление int i тогда выполнение вещи с i не приведет к проблемам, но если объявить Integer i, а затем сделать то же самое, возникнет NPE.

  • Проблемы равенства.

Рассмотрим этот код:

Integer i1 = 5;
Integer i2 = 5;

i1 == i2; // Currently would be false.

Было бы ложным.Операторы должны быть перегружены, и это приведет к значительному переписыванию содержимого.

  • Медленно

Обертки объектов значительно медленнее, чем их примитивные аналоги.

7 голосов
/ 05 марта 2011

Объекты гораздо более тяжелые, чем примитивные типы, поэтому примитивные типы гораздо более эффективны, чем экземпляры классов-оболочек.

Типы примитивов очень просты: например, int является 32-битным и занимает ровно 32 бита в памяти, и им можно манипулировать напрямую.Целочисленный объект - это законченный объект, который (как и любой объект) должен храниться в куче, и доступ к нему возможен только через ссылку (указатель) на него.Скорее всего, он также занимает более 32 бит (4 байта) памяти.

Тем не менее, тот факт, что в Java есть различие между примитивными и не примитивными типами, также является признаком возраста языка программирования Java.Более новые языки программирования не имеют этого различия;компилятор такого языка достаточно умен, чтобы самому определить, используете ли вы простые значения или более сложные объекты.

Например, в Scala нет примитивных типов;есть класс Int для целых чисел, а Int - это реальный объект (который вы можете использовать для методов и т. д.).Когда компилятор компилирует ваш код, он использует примитивные int за кулисами, поэтому использование Int так же эффективно, как использование примитива int в Java.

7 голосов
/ 05 марта 2011

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

5 голосов
/ 11 августа 2014
int loops = 100000000;

long start = System.currentTimeMillis();
for (Long l = new Long(0); l<loops;l++) {
    //System.out.println("Long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around Long: "+ (System.currentTimeMillis()- start));

start = System.currentTimeMillis();
for (long l = 0; l<loops;l++) {
    //System.out.println("long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around long: "+ (System.currentTimeMillis()- start));

Миллисекунды за цикл 100000000 вокруг Long: 468

Миллисекунды за цикл 100000000 раз вокруг длинного: 31

Кстати, я не прочь увидеть, как что-то подобное находит путь в Java.

Integer loop1 = new Integer(0);
for (loop1.lessThan(1000)) {
   ...
}

Где цикл for автоматически увеличивает loop1 от 0 до 1000 или

Integer loop1 = new Integer(1000);
for (loop1.greaterThan(0)) {
   ...
}

Где цикл for автоматически уменьшает loop1 1000 до 0.

5 голосов
/ 07 марта 2014

Примитивные типы имеют много преимуществ:

  • Более простой код для записи
  • Производительность лучше, так как вы не создаете экземпляр объекта для переменной
  • Поскольку они не представляют ссылку на объект, нет необходимости проверять наличие нулей
  • Используйте примитивные типы, если вам не нужны преимущества бокса.
5 голосов
/ 05 марта 2011

Трудно понять, какие оптимизации происходят под прикрытием.

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

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

Более того, Integer имеет гораздо более высокие логические издержки по сравнению с int: теперь вам нужно беспокоитьсяо том, будет ли int a = b + c; генерировать исключение.

Я бы максимально использовал примитивы и полагался на фабричные методы и автобокс, чтобы дать мне более семантически мощные коробочные типы, когда они необходимы.

2 голосов
/ 03 декабря 2016

Я согласен с предыдущими ответами, использование объектов-примитивов может быть дорогостоящим.Но если производительность не критична для вашего приложения, вы избегаете переполнения при использовании объектов.Например:

long bigNumber = Integer.MAX_VALUE + 2;

Значение bigNumber равно -2147483647, и вы ожидаете, что оно будет 2147483649. Это ошибка в коде, которая будет исправлена ​​с помощью:

long bigNumber = Integer.MAX_VALUE + 2l; // note that '2' is a long now (it is '2L').

И bigNumber будет 2147483649. Такие ошибки иногда легко пропустить и могут привести к неизвестному поведению или уязвимостям (см. CWE-190 ).

Если выиспользуйте объекты-обертки, эквивалентный код не будет компилироваться.

Long bigNumber = Integer.MAX_VALUE + 2; // Not compiling

Таким образом, с помощью объектов-оболочек примитивов проще остановить такие проблемы.

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

2 голосов
/ 08 сентября 2015
  1. Вам нужны примитивы для выполнения математических операций
  2. Примитивы занимают меньше памяти, как указано выше, и лучше работают

Вы должны спросить, почему требуется тип класса / объекта

Причина наличия Типа объекта состоит в том, чтобы облегчить нашу жизнь, когда мы имеем дело с Коллекциями.Примитивы не могут быть добавлены непосредственно в List / Map, вам нужно написать класс-оболочку.Здесь вам помогут классы Readymade Integer, а также множество вспомогательных методов, таких как Integer.pareseInt (str)

0 голосов
/ 12 июня 2019

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

С другой стороны, текущая спецификация языка Java не позволяет использовать примитивные типы в параметризованных типах (обобщениях), в коллекциях Java или Reflection API.

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

* Подробнее см. В источнике: https://www.baeldung.com/java-primitives-vs-objects

0 голосов
/ 12 декабря 2014

Потому что JAVA выполняет все математические операции в примитивных типах. Рассмотрим этот пример:

public static int sumEven(List<Integer> li) {
    int sum = 0;
    for (Integer i: li)
        if (i % 2 == 0)
            sum += i;
        return sum;
}

Здесь операции напоминания и унарного плюса не могут применяться к типу Integer (Reference), компилятор выполняет распаковку и выполняет операции.

Итак, убедитесь, сколько операций автобоксирования и распаковки происходит в java-программе. Поскольку для выполнения этой операции требуется время.

Как правило, лучше сохранять аргументы типа Reference и результат типа примитива.

...