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

Что такое Unboxing?

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

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

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

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

Unboxing в Java

Unboxing — это процесс, обратный boxing'у. Если boxing преобразует примитив в объект-обёртку, то unboxing преобразует объект обратно в примитив. Это может быть источником ошибок, если не понимать как это работает.

Определение

Unboxing — это автоматическое преобразование объекта-обёртки (wrapper class) в соответствующий примитивный тип.

// Boxing: примитив → объект
int primitiveInt = 42;
Integer boxedInt = primitiveInt;  // Auto-boxing
// JVM превращает это в: Integer.valueOf(primitiveInt)

// Unboxing: объект → примитив
Integer boxedInt = 42;
int primitiveInt = boxedInt;  // Auto-unboxing
// JVM превращает это в: boxedInt.intValue()

Как работает unboxing

Когда компилятор видит unboxing, он вызывает соответствующий метод:

Integer boxed = 100;
int unboxed = boxed;  // Компилятор преобразует в:
int unboxed = boxed.intValue();

// Для других типов:
Double d = 3.14;
double primitiveD = d;  // Вызовет d.doubleValue()

Boolean b = true;
boolean primitiveB = b;  // Вызовет b.booleanValue()

История: из прошлого без auto-unboxing

До Java 1.5 нужно было вручную выполнять unboxing:

// Java 1.4 (без auto-unboxing)
Integer boxed = new Integer(100);
int unboxed = boxed.intValue();  // Вручную!

// Java 1.5+ (с auto-unboxing)
Integer boxed = 100;
int unboxed = boxed;  // Компилятор делает это за нас

Примеры unboxing

1. В присваивании

Integer boxed = 42;
int primitive = boxed;  // Unboxing!

2. В арифметических операциях

Integer a = 5;
Integer b = 10;

int sum = a + b;  // Оба unbox'ятся и складываются
// Эквивалентно: int sum = a.intValue() + b.intValue();

Integer result = a + b;  // a + b unbox'ятся, затем результат box'ится

3. В сравнениях

Integer a = 100;
int b = 100;

if (a == b) {  // a unbox'ится
    System.out.println("Equal");
}

4. В методах

public void process(int value) {
    System.out.println(value);
}

Integer boxed = 42;
process(boxed);  // Unboxing перед вызовом

Опасный момент: NullPointerException

Самая частая ошибка — unboxing null:

Integer boxed = null;
int primitive = boxed;  // NullPointerException!
// При попытке вызвать: boxed.intValue()

Это может случиться и в менее очевидных случаях:

Integer boxed = getValue();  // Может вернуть null
int primitive = boxed;  // NPE если getValue() вернул null!

int sum = getValue1() + getValue2();  // NPE если одно из них null

Как защитить себя

1. Всегда проверяй на null перед unboxing

Integer boxed = getValue();
int primitive = boxed != null ? boxed : 0;  // Безопасно

2. Используй Optional

Optional<Integer> optInt = getOptional();
int primitive = optInt.orElse(0);  // Элегантно и безопасно

3. Используй статические методы

// getOrDefault лучше, чем ручное unboxing
Integer boxed = map.get(key);
int value = boxed != null ? boxed : defaultValue;

// А ещё лучше:
int value = map.getOrDefault(key, defaultValue);

Производительность unboxing

Unboxing имеет небольшую стоимость:

// Медленно: постоянный boxing/unboxing
Integer sum = 0;
for (int i = 0; i < 1000000; i++) {
    sum += i;  // Unbox sum, выполнить арифметику, box результат
}
// Это ОЧЕНЬ медленно!

// Быстро: работаем с примитивами
int sum = 0;
for (int i = 0; i < 1000000; i++) {
    sum += i;  // Никакого boxing/unboxing
}

Вот пример из реального проекта:

// ПЛОХО! Постоянное boxing/unboxing
List<Integer> numbers = new ArrayList<>();
Integer total = 0;
for (Integer num : numbers) {
    total += num;  // Unbox, добавить, box
}

// ХОРОШО! Работаем с примитивом
int total = 0;
for (Integer num : numbers) {
    total += num.intValue();  // Явно unbox один раз
}

// ИЛИ используй Stream API с mapToInt
int total = numbers.stream()
    .mapToInt(Integer::intValue)
    .sum();

Таблица wrapper классов

Примитив    Wrapper      Метод unboxing
---------------------------------------
int          Integer      intValue()
long         Long         longValue()
double       Double       doubleValue()
float        Float        floatValue()
boolean      Boolean      booleanValue()
byte         Byte         byteValue()
char         Character    charValue()
short        Short        shortValue()

Частые ошибки

Ошибка 1: NullPointerException

Integer value = null;
int x = value;  // NullPointerException!

Ошибка 2: Infinite unboxing в циклах

List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
    Integer value = i;  // Boxing
    list.add(value);
    int x = value;  // Unboxing
}
// Зачем boxing если потом unboxing?

Ошибка 3: Забывают про null в Stream API

list.stream()
    .map(i -> i + 1)  // Unboxing здесь!
    .forEach(System.out::println);
// Если в list есть null -> NullPointerException!

Лучшие практики

  1. Используй примитивы когда возможно — быстрее и безопаснее
  2. Работай с wrapper'ами только когда нужно — в коллекциях, Optional, Stream API
  3. Всегда проверяй на null перед unboxing
  4. Используй IntStream, LongStream для больших последовательностей — избежишь boxing/unboxing
  5. Профилируй критичный код — часто boxing/unboxing становятся bottleneck'ом

Unboxing — это нормальная часть Java, но нужно помнить о его существовании, особенно в критичном по производительности коде.

Что такое Unboxing? | PrepBro