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.
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
intis 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; // -2147483648Integer – Reference type
Integeris 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
intvalues 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
Integerobjects 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 valuesInteger 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 equalCache 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 Integerto 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
intoffers superior performance because it stores the value directly without object overhead. In tight numeric loops, using int can dramatically reduce execution time.
Integer advantage
Integerprovides 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"); // ~500msKey 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() workCase 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
intand 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!
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
