Quick Decision Guide

  • Use int for primitive number crunching, counters, loops, and performance-critical code.
  • Use Integer when you need null, work with collections/generics/Streams, use it as a map key, or interact with APIs that require objects.

What Are int and Integer?

  • int is a primitive 32-bit signed integer type.
    • Range: −2,147,483,648 to 2,147,483,647.
    • Stored directly on the stack or inside objects as a raw value.
  • Integer is the wrapper class for int (in java.lang).
    • An immutable object that contains an int value (or can be null).
    • Provides methods like compare, parseInt (static in Integer), etc.

Why Do We Have Two Types?

Java was designed with primitives for performance and memory efficiency. Later, Java introduced generics, Collections, and object-oriented APIs that need reference types. Wrapper classes (like Integer) bridge primitives and object APIs, enabling features primitives can’t provide (e.g., nullability, method parameters of type Object, use as generic type arguments).

Key Differences at a Glance

Aspectint (primitive)Integer (wrapper class)
NullabilityCannot be nullCan be null
Memory4 bytes for the valueObject header + 4 bytes value (+ padding)
PerformanceFast (no allocation)Slower (allocation, GC, boxing/unboxing)
Generics/CollectionsNot allowed as type parameterAllowed: List<Integer>
Default value (fields)0null
Equality== compares values== compares references; use .equals() for value
AutoboxingNot applicableWorks with int via autoboxing/unboxing
MethodsN/AUtility & instance methods (compareTo, hashCode, etc.)

Autoboxing & Unboxing (and the Gotchas)

Java will automatically convert between int and Integer:

Integer a = 5;    // autoboxing: int -> Integer
int b = a;        // unboxing: Integer -> int

Pitfall: Unboxing a null Integer throws NullPointerException.

Integer maybeNull = null;
int x = maybeNull; // NPE at runtime!

Tip: When a value can be absent, prefer OptionalInt/Optional<Integer> or check for null before unboxing.

Integer Caching (−128 to 127)

Integer.valueOf(int) caches values in [−128, 127]. This can make some small values appear identical by reference:

Integer x = 100;
Integer y = 100;
System.out.println(x == y);      // true (same cached object)
System.out.println(x.equals(y)); // true

Integer p = 1000;
Integer q = 1000;
System.out.println(p == q);      // false (different objects)
System.out.println(p.equals(q)); // true

Rule: Always use .equals() for value comparison with wrappers.

When to Use int

  • Counters, indices, arithmetic in tight loops.
  • Performance-critical code paths to avoid allocation/GC.
  • Fields that are always present (never absent) and don’t need object semantics.
  • Switch statements and bit-level operations.

Example:

int sum = 0;
for (int i = 0; i < nums.length; i++) {
  sum += nums[i];
}

When to Use Integer

  • Collections/Generics/Streams require reference types:
List<Integer> scores = List.of(10, 20, 30);

  • Nullable numeric fields (e.g., optional DB columns, partially populated DTOs).
  • Map keys or values where object semantics and equals/hashCode matter:
Map<Integer, String> userById = new HashMap<>();

  • APIs that expect Object or reflection/serialization frameworks.

Benefits of Each

Benefits of int

  • Speed & low memory footprint.
  • No NullPointerException from unboxing.
  • Straightforward arithmetic.

Benefits of Integer

  • Nullability to represent “unknown/missing”.
  • Works with Collections, Generics, Streams.
  • Provides utility methods and can be used in APIs requiring objects.
  • Immutability makes it safe as a map key.

When Not to Use Them

  • Avoid Integer in hot loops or large arrays where performance/memory is critical (boxing creates many objects).
    • Prefer int[] over List<Integer> when possible.
  • Avoid int when a value might be absent or needs to live in a collection or generic API.
  • Beware of unboxing nulls—if a value can be null, don’t immediately unbox to int.

Practical Patterns

1) DTO with Optional Field

class ProductDto {
  private Integer discountPercent; // can be null if no discount
  // getters/setters
}

2) Streams: Primitive vs Boxed

int sum = IntStream.of(1, 2, 3).sum();          // primitive stream: fast
int sum2 = List.of(1, 2, 3).stream()
                 .mapToInt(Integer::intValue)
                 .sum();                         // boxed -> primitive

3) Safe Handling of Nullable Integer

Integer maybe = fetchCount();           // might be null
int count = (maybe != null) ? maybe : 0; // avoid NPE

4) Overloads & Method Selection

If you provide both:

void setValue(int v) { /* ... */ }
void setValue(Integer v) { /* ... */ }

  • Passing a literal (setValue(5)) picks int.
  • Passing null only compiles for Integer (setValue(null)).

Common FAQs

Q: Why does List<int> not compile?
A: Generics require reference types; use List<Integer> or int[].

Q: Why does x == y sometimes work for small Integers?
A: Because of Integer caching (−128 to 127). Don’t rely on it—use .equals().

Q: I need performance but also collections—what can I do?
A: Use primitive arrays (int[]) or primitive streams (IntStream) to compute, then convert minimally when you must interact with object-based APIs.

Cheat Sheet

  • Performance: int > Integer
  • Nullability: Integer
  • Collections/Generics: Integer
  • Equality: int uses ==; Integer use .equals() for values
  • Hot loops / big data: prefer int / int[]
  • Optional numeric: Integer or OptionalInt (for primitives)

Mini Example: Mixing Both Correctly

class Scoreboard {
  private final Map<Integer, String> playerById = new HashMap<>(); // needs Integer
  private int totalScore = 0;                                      // fast primitive

  void addScore(int playerId, int score) {
    totalScore += score; // primitive math
    playerById.put(playerId, "Player-" + playerId);
  }

  Integer findPlayer(Integer playerId) {
    // Accepts null safely; returns null if absent
    return (playerId == null) ? null : playerId;
  }
}

Final Guidance

  • Default to int for computation and tight loops.
  • Choose Integer for nullability and object-centric APIs (Collections, Generics, frameworks).
  • Watch for NPE from unboxing and avoid boxing churn in performance-sensitive code.
  • Use .equals() for comparing Integer values; not ==.