Data Types

Master Java data types — primitives vs objects, type casting, autoboxing, and the gotchas that cause bugs in production.

Last reviewed: January 2025

·Java 8Java 11Java 17Java 21
✅
Quick Understanding: Java has two categories of data types: primitives (int, boolean, double, etc.) that store values directly on the stack, and reference types (String, Integer, List, etc.) that store a pointer to an object on the heap. This distinction affects performance, null safety, and how == works.

🔍 What Is It?

Primitive Types (8 total)

  • →byte: 8-bit signed, range -128 to 127
  • →short: 16-bit signed, range -32,768 to 32,767
  • →int: 32-bit signed, range -2^31 to 2^31-1 (default for integers)
  • →long: 64-bit signed, use L suffix: 100L
  • →float: 32-bit IEEE 754, use f suffix: 3.14f
  • →double: 64-bit IEEE 754 (default for decimals)
  • →char: 16-bit Unicode character, range 0 to 65,535
  • →boolean: true or false

Reference Types

  • →String — immutable sequence of characters
  • →Wrapper Classes — Integer, Long, Double, Boolean, etc. (primitives as objects)
  • →Arrays — fixed-size ordered collection
  • →Classes/Interfaces — any object type

Type Hierarchy

  • →All reference types extend Object
  • →Primitives do NOT extend Object (this is why generics don't support primitives directly)

🎯 Why Do We Need It?

Primitives exist for performance:

  • →An int is 4 bytes on the stack — direct value access
  • →An Integer is an object on the heap — pointer + object header overhead (~16 bytes)
  • →For a list of 1 million numbers, int[] uses ~4MB; List<Integer> uses ~20MB+

Reference types exist for:

  • →Null representation (primitives cannot be null)
  • →Object-oriented features (methods, inheritance)
  • →Collections API compatibility (generics require objects)
  • →Nullable database columns (Integer can be null, int cannot)

🏗️ What Happens in Real Projects?

Common patterns in enterprise code:

  • →Database mapping — use Integer (not int) for nullable columns
  • →Financial calculations — use BigDecimal (not double) for money
  • →Bit flags — use int or long for performance-critical flags
  • →Enums — prefer over int constants for type safety
  • →var keyword — use for local type inference (Java 10+)

⚙️ How It Works

Autoboxing/Unboxing

Java automatically converts between primitives and wrappers:

Integer boxed = 42;        // autoboxing: int -> Integer
int primitive = boxed;     // unboxing: Integer -> int

Integer Cache (-128 to 127)

Java caches Integer objects from -128 to 127. This is why == works for small integers but fails for larger ones — a classic interview trap.

String Pool

String literals are interned in the String Pool (part of Heap). Two literals with the same value share the same object. new String("hello") bypasses the pool.

💻 Example

Data Type Gotchas and Best Practices — The bugs that trip up developers who do not understand Java type internals.

java
// Integer cache: -128 to 127 are cached
Integer x = 127;
Integer y = 127;
System.out.println(x == y);  // true (same cached object)

Integer p = 128;
Integer q = 128;
System.out.println(p == q);  // FALSE! (different objects)
System.out.println(p.equals(q));  // true (always use equals)

// String pool
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);  // true (same pool object)

String s3 = new String("hello");
System.out.println(s1 == s3);  // FALSE! (new object on heap)
System.out.println(s1.equals(s3));  // true (always use equals)

// NullPointerException from unboxing
Integer nullableValue = null;  // from database: nullable column
int primitive = nullableValue;  // NPE! unboxing null throws NPE

🤔 Common Confusions

❓ Why does == sometimes work for Integer but not always?

Java caches Integer objects from -128 to 127. Within this range, Integer.valueOf() returns the same cached object, so == works. Outside this range, new objects are created, so == compares references (addresses), not values. Always use .equals() for object comparison.

❓ When should I use int vs Integer?

Use primitive int for local variables, method parameters, and array elements where null is not needed — it is faster and uses less memory. Use Integer (wrapper) for collections (List<Integer>), when null is a valid value (e.g., nullable DB column), and when you need the Integer utility methods.

❓ Why should I not use double for money?

double uses IEEE 754 binary floating-point which cannot exactly represent most decimal fractions (0.1, 0.2, etc.). This causes rounding errors that accumulate. For financial calculations, always use BigDecimal with String constructor. For performance-critical financial code, use long to store values in cents.

🚨 Common Production Issues

NullPointerException from unboxing null Integer — code like int x = getInteger() throws NPE if getInteger() returns null. Always check for null before unboxing.

Integer overflow silently wrapping — int max is ~2.1 billion. Counters, timestamps, and IDs can overflow silently. Use long for IDs and timestamps.

Float/double precision in financial reports — even tiny rounding errors multiply across millions of transactions. Use BigDecimal for all money.

String concatenation in loops — using + in a loop creates many String objects. Use StringBuilder for performance.

✅ Best Practices

Use primitives (int, long, boolean) for local variables and performance-critical code.

Use wrapper types (Integer, Long) only when null is needed or collections are involved.

Always use BigDecimal for monetary values; always use the String constructor.

Use equals() for all object comparisons; never use == for String or Integer.

Use long (not int) for IDs, timestamps, and counters that might exceed 2 billion.

Prefer enum over int constants for type safety and readability.

🏛️ Architect's Note

Senior Architect's Perspective

Java 22+ is working on Primitive Types in Generics (Project Valhalla) which will allow List<int> directly. This will eliminate the performance gap between primitives and generics. Until then, for performance-critical collections of primitives, use specialized libraries like Eclipse Collections or primitive arrays.

💬 Frequently Asked Questions

What is the difference between String, StringBuilder, and StringBuffer?

String is immutable — every modification creates a new object. StringBuilder is mutable and fast but NOT thread-safe — use it in single-threaded code and loops. StringBuffer is mutable and thread-safe (synchronized) but slower — rarely needed in modern code. In practice: use String for values, StringBuilder for building strings in loops.

What are text blocks in Java?

Text blocks (Java 15+) are multi-line string literals using triple quotes. They preserve indentation intelligently and are perfect for JSON, SQL, and HTML strings in code. Example: String json = """ { "name": "John" } """; They eliminate the need for string concatenation and escape characters in multi-line strings.

🎯 Key Takeaways

18 primitive types: byte, short, int, long, float, double, char, boolean
2Primitives store values on stack; reference types store pointers to heap objects
3Always use equals() for object comparison, never == (except for enum)
4Use BigDecimal for money, never float or double
5Integer cache covers -128 to 127 — a classic interview gotcha
6Use long for IDs and timestamps to avoid overflow

🎯 Practice this topic in interviews

↗ Where this topic fits

Sources

Sources / References

Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.

Related SplashRide pages

SplashRide Core Java learning path

Browse the full Core Java topic collection and learning order on SplashRide.

Core Java Interview Prep

Practice Core Java interview questions and scenario-based answers.

Backend Engineer Career Path

A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.

Full Stack Java Developer Career Path

A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.

Operators

Master Java operators — arithmetic, comparison, logical, bitwise, and the ternary operator — with the precedence rules that cause subtle bugs.

Classes & Objects

The foundation of Java OOP — how classes define blueprints and objects are instances, with constructors, fields, methods, and the this keyword.