← Назад к вопросам

Можно ли в ArrayList хранить примитивные типы?

1.6 Junior🔥 101 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Можно ли хранить примитивные типы в ArrayList

Нет, ArrayList НЕ может напрямую хранить примитивные типы (int, double, boolean и т.д.), только их обёрнутые версии (Integer, Double, Boolean и т.д.). Это связано с особенностями generics и типизации Java.

Почему примитивы нельзя хранить в ArrayList

// ❌ Это вызовет ошибку компилятора
ArrayList<int> numbers = new ArrayList<int>();
// error: unexpected type

// ✅ Нужно использовать обёртки
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(42);

Почему это ограничение существует:

  1. Generics работают только с типами (Reference Types), не примитивами

    // ArrayList<T> — T должен быть типом (class)
    // int, double, boolean — это примитивы, не типы
    
  2. Type Erasure в compile-time

    // Во время компиляции ArrayList<Integer> становится ArrayList<Object>
    // Примитивы не могут быть Object
    ArrayList<Integer> list = new ArrayList<Integer>();
    // После Type Erasure: ArrayList list (Object'ы)
    
  3. Null-safety: примитивы не могут быть null

    Integer value = null; // ОК, Integer может быть null
    int value2 = null;    // Ошибка, int не может быть null
    

Решение: Boxing и Unboxing

Boxing — это автоматическое преобразование примитива в обёртку:

// Manual Boxing (старый способ)
ArrayList<Integer> numbers = new ArrayList<Integer>();
Integer boxed = Integer.valueOf(42);
numbers.add(boxed);
int unboxed = numbers.get(0).intValue();

// Auto-boxing (современный способ, Java 5+)
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(42);              // Автоматически boxing: int → Integer
int value = numbers.get(0);   // Автоматически unboxing: Integer → int

Вот что происходит под капотом:

public class IntegerBoxing {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        
        // Это:
        list.add(10);
        
        // Компилятор преобразует в:
        list.add(Integer.valueOf(10)); // Boxing
        
        // А это:
        int x = list.get(0);
        
        // Компилятор преобразует в:
        int x = list.get(0).intValue(); // Unboxing
    }
}

Все примитивные типы и их обёртки

ПримитивОбёрткаПример
byteByteArrayList<Byte>
shortShortArrayList<Short>
intIntegerArrayList<Integer>
longLongArrayList<Long>
floatFloatArrayList<Float>
doubleDoubleArrayList<Double>
booleanBooleanArrayList<Boolean>
charCharacterArrayList<Character>

Практические примеры

1. Работа с числами

// ✅ Правильно
ArrayList<Integer> scores = new ArrayList<>();
scores.add(95);      // Автоматический boxing
scores.add(87);
scores.add(92);

for (Integer score : scores) {
    System.out.println("Score: " + score);
}

// Вычисление среднего
int sum = 0;
for (int score : scores) { // Автоматический unboxing
    sum += score;
}
double average = sum / (double) scores.size();

2. Работа с булеанами

ArrayList<Boolean> flags = new ArrayList<>();
flags.add(true);
flags.add(false);
flags.add(true);

for (Boolean flag : flags) {
    if (flag) {
        System.out.println("Flag is set");
    }
}

3. NullPointerException при unboxing null

ArrayList<Integer> list = new ArrayList<>();
list.add(null);

// ❌ Ошибка: NPE при распаковке null
int value = list.get(0); // NullPointerException!
// Компилятор пытается: list.get(0).intValue()
// А list.get(0) вернул null

// ✅ Правильно: проверь на null
Integer value = list.get(0);
if (value != null) {
    int intValue = value;
}

// Или
int value = list.get(0) != null ? list.get(0) : 0; // Дефолт 0

Проблемы с автоматическим boxing/unboxing

1. Производительность: создание лишних объектов

// ❌ Неэффективно
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
    list.add(i); // Каждый int преобразуется в Integer объект
}
// Потреблено 1млн объектов в памяти!

// ✅ Эффективнее (если нужна именно последовательность)
int[] array = new int[1_000_000];
for (int i = 0; i < 1_000_000; i++) {
    array[i] = i; // Никаких объектов, только примитивы
}

2. Производительность: Autoboxing в циклах

// Плохо: много boxing/unboxing
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 100_000; i++) {
    list.add(i); // Boxing
    
    Integer value = list.get(i); // Получаем Integer
    int x = value;               // Unboxing
    int result = x + 10;         // Арифметика
}

// Лучше: используй примитивный массив
int[] array = new int[100_000];
for (int i = 0; i < 100_000; i++) {
    array[i] = i;
    
    int value = array[i];  // Никакого boxing/unboxing
    int result = value + 10;
}

Альтернативы для работы с примитивами

1. Примитивные массивы (если известен размер)

int[] numbers = new int[10];
numbers[0] = 42;
numbers[1] = 100;

// Преимущества: нет boxing, быстро, меньше памяти
// Недостатки: фиксированный размер, нет методов ArrayList

2. Специальные коллекции для примитивов (библиотеки)

// Библиотека Apache Commons
import org.apache.commons.collections4.list.SetUniqueList;

// Или использование специализированных структур
// Например, IntStream для работы с int
List<Integer> list = java.util.stream.IntStream.range(0, 100)
    .boxed()
    .collect(java.util.stream.Collectors.toList());

// Или через Stream API
List<Integer> squares = java.util.stream.IntStream.range(0, 10)
    .map(i -> i * i)
    .boxed()
    .collect(java.util.stream.Collectors.toList());

3. Интрузивные коллекции (Primitive Collections)

// Используя библиотеку like Trove или Koloboke
// TIntArrayList из Trove — это ArrayList для int без boxing
import gnu.trove.list.array.TIntArrayList;

TIntArrayList list = new TIntArrayList();
list.add(42);
list.add(100);
// Все int'ы хранятся как примитивы, без object overhead

for (int value : list.toArray()) {
    System.out.println(value);
}

Пример из реальной IKEA системы

// Хранение рейтингов товаров (целые числа 1-5)

// ❌ Неэффективно для большого объёма
ArrayList<Integer> ratings = new ArrayList<>();
for (int i = 0; i < 10_000_000; i++) {
    ratings.add((int)(Math.random() * 5 + 1));
}
// Создано 10млн Integer объектов!

// ✅ Правильно: примитивный массив
int[] ratings = new int[10_000_000];
for (int i = 0; i < 10_000_000; i++) {
    ratings[i] = (int)(Math.random() * 5 + 1);
}
// Только 40MB памяти вместо 100+MB

// ✅ Для гибкого размера: специализированная коллекция
// или примитивные потоки
List<Integer> ratingList = java.util.stream.IntStream
    .generate(() -> (int)(Math.random() * 5 + 1))
    .limit(10_000_000)
    .boxed()
    .collect(java.util.stream.Collectors.toList());

Заключение

ВопросОтвет
Можно ли в ArrayList<int>?❌ Нет, ошибка компилятора
Можно ли в ArrayList<Integer>?✅ Да, с автоматическим boxing
Как это работает?Компилятор автоматически boxing примитив → обёртка
Есть ли проблемы?⚠️ Производительность (создание объектов, null)
Когда использовать?Когда нужна гибкость ArrayList, малые объёмы данных
Альтернатива?Примитивные массивы, специализированные коллекции

Золотое правило: если работаешь с миллионами чисел и нужна максимальная производительность — используй примитивные массивы или специализированные коллекции. Если малый объём и нужна гибкость — ArrayList<Integer> с auto-boxing вполне приемлем.

Можно ли в ArrayList хранить примитивные типы? | PrepBro