Fundamentals 22 min read

7 Crucial Differences Between Java int and Integer You Must Know

This article explains the seven key differences between Java's primitive int and its wrapper Integer, covering default values, memory layout, comparison pitfalls, caching, autoboxing/unboxing, performance impact, and appropriate usage scenarios with concrete code examples and benchmarks.

Java Tech Workshop
Java Tech Workshop
Java Tech Workshop
7 Crucial Differences Between Java int and Integer You Must Know

Introduction

In Java programming, int and Integer are the two most commonly used data types, but many developers confuse them. One is a primitive type, the other a wrapper class; they look similar but hide many traps. This article analyses the seven critical differences to help you avoid common pitfalls.

1. Data Type Essence: Primitive vs Reference

int – Primitive type

int

is one of Java's eight primitive types. It stores the numeric value directly without object‑header overhead. In memory, int occupies 4 bytes (32 bits) and can represent values from –2,147,483,648 to 2,147,483,647.

Core characteristic: int is a value type; the variable holds the value itself. Declaring an int variable and assigning a value stores the value directly at the variable's memory location, making access very fast because no dereferencing is required.

int num = 10; // directly stores value 10, occupies 4 bytes
int maxValue = Integer.MAX_VALUE; // 2147483647
int minValue = Integer.MIN_VALUE; // -2147483648

Integer – Reference type

Integer

is the wrapper class for int, belonging to the reference‑type family. The variable stores a reference to an Integer object on the heap rather than the raw value.

Core characteristic: Integer is an object type that encapsulates the primitive int. The object contains the integer value and provides a rich set of methods. Because it is an object, it can be null, which is useful in certain business scenarios.

Integer num = new Integer(10); // creates a new object, stores a reference
Integer num2 = Integer.valueOf(10); // may reuse cached object
Integer num3 = 10; // autoboxing, equivalent to Integer.valueOf(10)

Trap reminder: When Integer is null, calling any method on it throws a NullPointerException. This is a very common error that requires special attention.

Integer nullInt = null;
nullInt.intValue(); // NullPointerException!

2. Default Value Differences

Default value of int

For class fields, the JVM automatically initializes an int to 0. Local variables are not automatically initialized; the compiler will report an error if they are used without explicit assignment.

public class Test {
    static int num; // class field, default 0
    public static void main(String[] args) {
        System.out.println(num); // prints 0
        int localNum; // local variable, not initialized
        System.out.println(localNum); // compile error
    }
}

Default value of Integer

Reference types default to null. If a class field of type Integer is not assigned, its value is null.

public class Test {
    static Integer num; // default null
    public static void main(String[] args) {
        System.out.println(num); // prints null
        Integer localNum; // also not initialized
        System.out.println(localNum); // compile error
    }
}

Practical impact: In database operations or JSON serialization, null and 0 have completely different semantics. For example, an unset age field may be stored as null to indicate "unknown", whereas 0 means an explicit value of zero.

3. Memory Storage Location

int storage

int

values are stored on the stack when used as local variables, or inside the object heap when they are fields. Stack memory offers fast access but limited space and a short lifetime.

Performance advantage: Because int stores the value directly, access is extremely fast—no extra dereferencing is needed.

public class MemoryDemo {
    int instanceField; // stored in heap as part of the object
    public void method() {
        int localVar = 10; // stored on the stack
    }
}

Integer storage

Integer

objects reside on the heap and are accessed via a stack reference. The heap provides larger space and longer lifetimes, but access is slower due to dereferencing.

Memory structure: An Integer object typically consists of an object header (Mark Word, Klass Pointer, etc.) plus the 4‑byte integer value. In a 64‑bit JVM the header is about 16 bytes, so the total size is roughly 20 bytes—much larger than the 4 bytes of an int.

┌─────────────────────────────────────┐
│            Heap Memory              │
│  ┌───────────────────────────────┐ │
│  │   Integer object               │ │
│  │  ┌─────────────┐ ┌───────────┐ │
│  │  │ Mark Word   │ │ Klass Ptr │ │
│  │  └─────────────┘ └───────────┘ │
│  │  ┌─────────────────────┐      │
│  │  │ int value (4 bytes) │      │
│  │  └─────────────────────┘      │
│  └───────────────────────────────┘ │
└─────────────────────────────────────┘

Performance impact: Frequent creation of Integer objects adds pressure to the garbage collector because each object carries additional overhead.

4. Comparison with == – The Trap

int comparison

Using == on int compares the numeric values directly. This is the fastest and most straightforward way to test equality.

int a = 10;
int b = 10;
System.out.println(a == b); // true, compares values

Integer comparison

When Integer objects are compared with ==, the comparison checks reference identity, not the numeric value. Two distinct Integer objects that hold the same value may not be ==.

Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println(a == b); // false, different objects
System.out.println(a.equals(b)); // true, values are equal

Cache trap: Integer.valueOf() caches objects for values in the range –128 to 127. Within this range, == may return true because the same cached instance is reused; outside the range, a new object is created and == returns false.

Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // true (cache hit)

Integer c = Integer.valueOf(200);
Integer d = Integer.valueOf(200);
System.out.println(c == d); // false (outside cache)

The source of Integer.valueOf() is:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

The cache upper bound can be adjusted with the JVM option -Djava.lang.Integer.IntegerCache.high=500.

5. Autoboxing and Unboxing

Autoboxing

Autoboxing automatically converts a primitive int to an Integer object by invoking Integer.valueOf().

Integer num = 10; // equivalent to Integer.valueOf(10)
List<Integer> list = new ArrayList<>();
list.add(5); // autoboxing to Integer.valueOf(5)

Unboxing

Unboxing automatically converts an Integer object to a primitive int by calling intValue().

Integer num = null;
int value = num; // NullPointerException!

Reminder 1: Unboxing a null reference throws NullPointerException.

Reminder 2 (ternary operator): In a ternary expression, the Integer branch is unboxed if the other branch is an int, which can cause NPE.

Integer a = null;
boolean flag = false;
int result = flag ? a : 0; // NullPointerException!

Reminder 3 (method call): Passing a

null
Integer

to a method that expects an int triggers unboxing and NPE.

public static void process(int value) {
    System.out.println(value);
}
Integer num = null;
process(num); // NullPointerException!

6. Performance Differences

int advantage

int

offers superior performance because it stores the value directly without object overhead. In tight numeric loops, using int can dramatically reduce execution time.

Integer advantage

Integer

provides functionality such as null representation, use in generic collections, and utility methods like parseInt() and toString().

Performance test:

// int loop 100 million iterations
long start = System.currentTimeMillis();
int sum = 0;
for (int i = 0; i < 100_000_000; i++) {
    sum += i;
}
long end = System.currentTimeMillis();
System.out.println("int time: " + (end - start) + "ms"); // ~5ms

// Integer loop 100 million iterations (boxing/unboxing each iteration)
start = System.currentTimeMillis();
Integer sum2 = 0;
for (int i = 0; i < 100_000_000; i++) {
    sum2 += i; // unbox, add, box again
}
end = System.currentTimeMillis();
System.out.println("Integer time: " + (end - start) + "ms"); // ~500ms

Key observations from the benchmark:

Memory usage: int uses 4 bytes, Integer roughly 20 bytes (object header + value).

Creation overhead: int allocation is negligible; Integer requires object allocation or cache lookup.

Access speed: stack‑resident int is faster than heap‑resident Integer which needs dereferencing.

GC impact: many short‑lived Integer objects increase garbage‑collection pressure.

7. Recommended Usage Scenarios

Prefer int when

Local variables and method parameters – better performance.

Array elements – int[] is more efficient than Integer[].

Frequent arithmetic – avoid boxing/unboxing overhead.

High‑performance computing such as scientific calculations or game engines.

public int calculateSum(int[] numbers) {
    int sum = 0;
    for (int num : numbers) {
        sum += num;
    }
    return sum;
}

Prefer Integer when

Working with Java collections (List, Set, Map) – generics require reference types.

Database fields that may be null – use Integer to represent missing values.

JSON serialization where null must be distinguished from zero.

Generic type parameters – primitives are not allowed.

public class User {
    private Integer age; // may be null if not provided
    public Integer getAge() { return age; }
}

Common Case Analyses

Case 1 – HashMap key comparison

When a HashMap uses Integer keys, the map internally calls equals(). Using == on keys can lead to unexpected results because it compares references.

Map<Integer, String> map = new HashMap<>();
map.put(new Integer(1), "one");
System.out.println(map.get(1)); // "one" – autoboxing and equals() work

Case 2 – Database query returning nullable integer

Calling ResultSet.getInt() on a nullable column converts null to 0, losing the distinction. Use ResultSet.getObject(..., Integer.class) to obtain an Integer that can be null.

// Wrong
int count = resultSet.getInt("count"); // null becomes 0

// Correct
Integer count = resultSet.getObject("count", Integer.class);

Case 3 – Ternary operator type inference

If one branch of a ternary expression is Integer and the other is int, the Integer side is unboxed, which can cause NPE when the Integer is null. Ensure both branches are of the same reference type.

Integer a = null;
int b = true ? a : 0; // NullPointerException!

// Safe version
Integer b = true ? a : Integer.valueOf(0);

Case 4 – Method overload resolution

When overloaded methods accept int and Integer, the compiler chooses the most specific match. Passing null selects the Integer overload; passing a literal selects the int overload.

public void process(int value) { System.out.println("int: " + value); }
public void process(Integer value) { System.out.println("Integer: " + value); }

process(10); // calls process(int)
process(Integer.valueOf(10)); // calls process(Integer)
process(null); // calls process(Integer)

Summary

Core Takeaways

Primitive types ( int) prioritize performance, have value semantics, and cannot be null.

Wrapper types ( Integer) prioritize functionality, have object semantics, and can represent null.

Practical Checklist

Default to int unless you need null or collection compatibility.

Use Integer for generic containers (List, Set, Map).

Compare Integer values with equals(), not ==.

Check for null before unboxing to avoid NPE.

Prefer Integer.valueOf() over new Integer() to benefit from caching.

Choose the type based on whether the database column allows null.

In performance‑critical code, use primitive arrays ( int[]) instead of collections.

Code Style Example

// Recommended style
public class BestPractice {
    // 1. Use int for local calculations
    public int calculate(int a, int b) {
        int result = a + b;
        return result;
    }

    // 2. Use Integer for nullable values
    public String formatAge(Integer age) {
        if (age == null) {
            return "Age not provided";
        }
        return "Age: " + age;
    }

    // 3. Collections must use Integer
    public List<Integer> getNumbers() {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1); // autoboxing
        numbers.add(2);
        return numbers;
    }

    // 4. Safe comparison
    public boolean compare(Integer a, Integer b) {
        return Objects.equals(a, b); // handles null safely
    }
}

Conclusion

int

and Integer may look simple, but they hide many pitfalls. Understanding their differences helps you avoid common bugs and write more efficient, robust Java code. Remember: primitives chase performance, wrappers chase functionality . Choose the right type for the right scenario.

Feel free to share the int / Integer traps you have encountered in the comments. If you found this article helpful, please like and follow for more Java insights!

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaperformanceintmemoryautoboxingnull handlingInteger
Java Tech Workshop
Written by

Java Tech Workshop

Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.