What are Java's wrapper classes, why do they exist, and when should you prefer one over the primitive?
A wrapper class wraps a primitive in an object: Integer for int, Double for double, Boolean for boolean, and so on for all eight primitives plus the two special cases Character and Void. Each wrapper is a final class with a single private field holding the primitive value.
They exist for three reasons. First, generics cannot be instantiated with primitives — the type argument List<Integer> is legal, List<int> is not, so anything that must live inside a collection, a stream or an Optional needs a wrapper. Second, the class library predates generics and had to support objects, so APIs like the older collection classes were designed around wrappers. Third, wrappers carry behaviour that primitives cannot: Integer.parseInt, Integer.toBinaryString, Character.isDigit, Boolean.parseBoolean and the value-comparison methods all live on the wrapper.
Where you should prefer the primitive: fields, method parameters and return types on hot paths. A wrapper is a heap object, so a field of type Integer holds a reference that must be dereferenced, may be null, and adds garbage-collection pressure. A field of type int holds the value inline with no reference and no null possibility.
Where you should prefer the wrapper: generic containers, optional values, and APIs that demand an object type. The recurring trap is that a wrapper can be null while a primitive cannot, and any operation that unboxes a null wrapper throws a NullPointerException at the point of use, often far from where the null was introduced.