Wrapper Classes & Autoboxing

Collections and generics work only with objects, not primitives — you can't have a List<int>. Each primitive type therefore has a wrapper class (Integer, Double, Boolean…), and Java converts between the two automatically. That convenience has a few traps worth knowing.

The wrapper classes

PrimitiveWrapper
intInteger
longLong
doubleDouble
booleanBoolean
charCharacter
byte, short, floatByte, Short, Float

Autoboxing and unboxing

JAVA
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> scores = new ArrayList<>();
        scores.add(72);
        scores.add(88);
        int first = scores.get(0);
        Integer boxed = 5;
        int sum = boxed + first;
        System.out.println(scores + " " + sum);
    }
}
Output
[72, 88] 77

Autoboxing wraps a primitive in an object when one is needed (scores.add(72)); unboxing extracts the primitive (int first = …). It happens silently in assignments, method calls and arithmetic.

Useful static methods

JAVA
public class Main {
    public static void main(String[] args) {
        System.out.println(Integer.parseInt("250") + 1);
        System.out.println(Integer.valueOf("42"));
        System.out.println(Integer.toBinaryString(10));
        System.out.println(Integer.toHexString(255));
        System.out.println(Integer.compare(3, 7));
        System.out.println(Double.isNaN(0.0 / 0.0));
        System.out.println(Character.isDigit('7') + " " + Character.isLetter('x') + " " + Character.toUpperCase('q'));
        System.out.println(Boolean.parseBoolean("TRUE"));
    }
}
Output
251
42
1010
ff
-1
true
true true Q
true

Trap 1: comparing with ==

JAVA
public class Main {
    public static void main(String[] args) {
        Integer a = 100, b = 100;
        Integer c = 1000, d = 1000;
        System.out.println(a == b);
        System.out.println(c == d);
        System.out.println(c.equals(d));
    }
}
Output
true
false
true

== on wrapper objects compares references. Java caches small values (−128 to 127), so 100 == 100 happens to be true while 1000 == 1000 isn't. Always compare wrappers with equals, or unbox them first.

Trap 2: null unboxing

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("mug", 12);
        int mugs = stock.get("mug");
        System.out.println(mugs);
        int lamps = stock.get("lamp");
    }
}
Output
12
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
    at Main.main(Main.java:10)

A wrapper can be null; a primitive can't. Unboxing null throws a NullPointerException. Use getOrDefault for maps (lesson 42), or check for null.

Trap 3: performance

JAVA
public class Main {
    public static void main(String[] args) {
        long primitive = 0;
        for (int i = 0; i < 1_000_000; i++) primitive += i;

        Long boxed = 0L;
        for (int i = 0; i < 1_000_000; i++) boxed += i;

        System.out.println(primitive == boxed);
    }
}
Output
true

Both loops give the same answer, but the second creates up to a million Long objects. In hot loops, use primitives; specialised streams (IntStream, lesson 46) avoid boxing too.

When to use which

  • Use primitives for local variables, fields and calculations.
  • Use wrappers where objects are required: collections, generics, and when null genuinely means "no value" (an optional database column, for example).

Try it yourself

Count the digits, letters and other characters in a string using Character methods.

Try it yourself · Main.java
Edit the code, copy it into Main.java and run java Main.java (Java 25+). How to set up Java
Output
digits=10 letters=13 other=7