Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Классы-обёртки

У каждого примитивного типа есть класс-обёртка — класс, объект которого хранит одно значение этого типа: int → Integer, double → Double, boolean → Boolean, char → Character (а также Long, Short, Byte, Float). Обёртки нужны там, где Java принимает только объекты: в коллекциях и в обобщённых типах.

Объект вместо числа

Метод Integer.valueOf() упаковывает число в объект, а intValue() достаёт его обратно:

void main() {
    Integer box = Integer.valueOf(42);
    int number = box.intValue();
    IO.println(box);
    IO.println(number + 1);
}

Результат:

42
43

У других обёрток методы называются так же: Double.valueOf() и doubleValue(), Boolean.valueOf() и booleanValue().

Автоупаковка и распаковка

Вызывать эти методы вручную почти никогда не нужно. Java сама упаковывает примитив в объект (автоупаковка) и распаковывает объект обратно (распаковка), когда типы не совпадают:

void main() {
    Integer count = 5;
    int next = count + 1;
 
    List<Double> prices = new ArrayList<>();
    prices.add(9.99);
    double first = prices.get(0);
 
    IO.println(next);
    IO.println(first);
}

Результат:

6
9.99

В строке count + 1 объект распаковался в int, а в prices.add(9.99) число упаковалось в Double. Списки и словари подробно разобраны в главе о коллекциях — здесь достаточно знать, что они хранят только объекты.

Полезные методы

Обёртки — ещё и наборы готовых методов для своего типа. Integer.parseInt() уже знаком по уроку о преобразовании типов, а вот другие:

void main() {
    IO.println(Integer.MAX_VALUE);
    IO.println(Integer.compare(3, 7));
    IO.println(Character.isDigit('7'));
    IO.println(Character.isLetter('ж'));
    IO.println(Character.toUpperCase('ж'));
    IO.println(Boolean.parseBoolean("true"));
}

Результат:

2147483647
-1
true
true
Ж
true

Integer.compare(a, b) возвращает отрицательное число, ноль или положительное — в зависимости от того, какое число больше.

null вместо значения

Переменная примитивного типа всегда хранит число, а переменная-обёртка может хранить null — «значения нет». Это удобно, когда отсутствие значения отличается от нуля:

void main() {
    Integer bonus = null;
    IO.println("Бонус: " + bonus);
}

Результат:

Бонус: null

Сравнение через ==

Оператор == для объектов проверяет, один ли это объект, а не равны ли значения. Java заранее создаёт объекты Integer для чисел от −128 до 127 и переиспользует их — это кеш Integer. Поэтому для маленьких чисел == случайно работает, а для больших — нет:

void main() {
    Integer a = 127;
    Integer b = 127;
    IO.println(a == b);
 
    Integer c = 128;
    Integer d = 128;
    IO.println(c == d);
    IO.println(c.equals(d));
}

Результат:

true
false
true

Значения обёрток сравнивайте методом equals() или распакуйте их в int.

Частая ошибка

Если распаковать null, программа упадёт с NullPointerException. Чаще всего это случается со словарём: get() для отсутствующего ключа возвращает null, а переменная int не может его принять:

void main() {
    Map<String, Integer> stock = Map.of("яблоки", 10);
    int pears = stock.get("груши");
    IO.println(pears);
}

Результат:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null

Используйте stock.getOrDefault("груши", 0) или сохраняйте результат в переменную Integer и проверяйте её на null.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.