Skip to content
Laviyx Learn

Try

Java course menu

Java Wrapper Classes and Autoboxing: Integer, Double, Character and More

Learn Java wrapper classes (Integer, Double, Boolean, Character, Long): why collections need them, autoboxing and unboxing, comparing Integer objects with equals, the Integer cache, NullPointerException when unboxing null, and useful static helper methods.

Beginner9 min readUpdated
On this page

Java's eight primitive types (int, double, char, …) are not objects. But many parts of Java, most importantly the collections (ArrayList, HashMap, …), can only hold objects. For that, each primitive type has a matching wrapper class.

PrimitiveWrapper class
intInteger
longLong
doubleDouble
floatFloat
booleanBoolean
charCharacter
byteByte
shortShort

Why wrappers exist#

Java
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // List<int> numbers;        // does not compile: type arguments must be objects
        List<Integer> numbers = new ArrayList<>();
        numbers.add(10);             // the int 10 is wrapped automatically
        numbers.add(20);

        int first = numbers.get(0);  // unwrapped automatically
        System.out.println(first + numbers.get(1));
    }
}
Output
30

Autoboxing and unboxing#

Java converts between primitives and wrappers automatically:

  • Autoboxing: int → Integer, for example when adding to a list.
  • Unboxing: Integer → int, for example in arithmetic.
Java
public class Main {
    public static void main(String[] args) {
        Integer boxed = 42;           // autoboxing
        int plain = boxed;            // unboxing
        Integer sum = boxed + plain;  // unbox, add, box again
        System.out.println(sum);

        Double price = 9.99;
        double total = price * 3;
        System.out.println(total);
    }
}
Output
84
29.97

Comparing wrapper objects: use equals#

== on two wrapper objects compares references, which leads to one of Java's most famous surprises:

Java
public class Main {
    public static void main(String[] args) {
        Integer a = 127;
        Integer b = 127;
        Integer c = 128;
        Integer d = 128;

        System.out.println(a == b);
        System.out.println(c == d);
        System.out.println(c.equals(d));
        System.out.println(c.intValue() == d.intValue());
    }
}
Output
true
false
true
true

Java caches Integer objects for values from −128 to 127, so small values happen to share an object and == seems to work. Outside that range, each boxing creates a new object. Always compare wrapper values with equals (or unbox them first).

Unboxing null throws#

A wrapper variable can be null, but a primitive cannot. Unboxing null throws a NullPointerException:

Java
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> stock = new HashMap<>();
        stock.put("pens", 40);

        Integer books = stock.get("books");   // null: no such key
        System.out.println(books);

        try {
            int count = stock.get("books");   // unboxing null
            System.out.println(count);
        } catch (NullPointerException e) {
            System.out.println("Cannot unbox a missing value");
        }

        int safe = stock.getOrDefault("books", 0);
        System.out.println(safe);
    }
}
Output
null
Cannot unbox a missing value
0

Map.getOrDefault avoids the problem. You will see maps in HashMap and TreeMap.

Useful static methods#

Wrapper classes are also toolboxes of conversion and checking methods:

Java
public class Main {
    public static void main(String[] args) {
        int n = Integer.parseInt("250");
        double d = Double.parseDouble("3.5");
        boolean flag = Boolean.parseBoolean("TRUE");

        System.out.println(n + d + " " + flag);
        System.out.println(Integer.max(3, 9) + " " + Integer.toBinaryString(10) + " " + Integer.toHexString(255));
        System.out.println(Integer.compare(5, 8) + " " + Integer.valueOf(7).equals(7));

        System.out.println(Character.isLetter('a') + " " + Character.isDigit('5') + " " + Character.toUpperCase('q'));
        System.out.println(Double.isNaN(0.0 / 0.0) + " " + Integer.MAX_VALUE);
    }
}
Output
253.5 true
9 1010 ff
-1 true
true true Q
true 2147483647

Integer.parseInt returns an int; Integer.valueOf returns an Integer (and uses the cache).

Performance#

Wrapper objects take more memory than primitives and add the cost of boxing. For large amounts of numeric data in tight loops, prefer primitive arrays (int[]) or primitive streams (IntStream). For ordinary collections, wrappers are perfectly fine.

Common mistakes#

Practice#

Practice exercise

Given String[] inputs = {"12", "7", "abc", "30"};, convert each valid number into a List<Integer> (skipping invalid ones), then print the list and its sum.

Show solution
Java
import java.util.ArrayList;
import java.util.List;

public class ParseAll {
    public static void main(String[] args) {
        String[] inputs = {"12", "7", "abc", "30"};
        List<Integer> numbers = new ArrayList<>();

        for (String s : inputs) {
            try {
                numbers.add(Integer.parseInt(s));
            } catch (NumberFormatException e) {
                System.out.println("Skipping " + s);
            }
        }

        int sum = 0;
        for (int n : numbers) sum += n;
        System.out.println(numbers + " sum " + sum);
    }
}
Output
Skipping abc
[12, 7, 30] sum 49

Key takeaway#

Finished this lesson?