Primitive data types are Java's built-in types for simple values — numbers, single characters and true/false. There are exactly eight: byte, short, int, long, float, double, char and boolean. In test automation you use them all the time: counters, timeouts, prices to verify, flags for pass/fail.

🎯 What you'll learn
  • All 8 primitive types with their exact size, range and default value
  • Which type to choose for counts, money, timeouts and flags
  • The difference between primitive and non-primitive (reference) types
  • Five traps — overflow, integer division, 0.1 + 0.2, char arithmetic and casting — with real output

The 8 Primitive Data Types

These values were printed by Java 21 itself (program below):

TypeSizeRangeDefault valueTypical use
byte8 bits-128 to 1270Raw bytes (files, images)
short16 bits-32,768 to 32,7670Rarely used
int32 bits-2,147,483,648 to 2,147,483,6470Counters, sizes, indexes — the default choice
long64 bitsabout ±9.2 × 10180Timestamps, very large counts
float32 bitsabout ±3.4 × 1038 (~7 digits precise)0.0Rarely needed
double64 bitsabout ±1.8 × 10308 (~15 digits precise)0.0Decimal numbers — the default choice
char16 bits0 to 65,535 (a Unicode character)'\u0000'A single character
boolean—true or falsefalseFlags: isVisible, isPassed
public class PrimitiveTypes {
    static byte b; static short s; static int i; static long l;
    static float f; static double d; static char c; static boolean bool;

    public static void main(String[] args) {
        System.out.println("byte    " + Byte.SIZE + " bits  " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE);
        System.out.println("short   " + Short.SIZE + " bits  " + Short.MIN_VALUE + " to " + Short.MAX_VALUE);
        System.out.println("int     " + Integer.SIZE + " bits  " + Integer.MIN_VALUE + " to " + Integer.MAX_VALUE);
        System.out.println("long    " + Long.SIZE + " bits  " + Long.MIN_VALUE + " to " + Long.MAX_VALUE);
        System.out.println("float   " + Float.SIZE + " bits  max " + Float.MAX_VALUE);
        System.out.println("double  " + Double.SIZE + " bits  max " + Double.MAX_VALUE);
        System.out.println("char    " + Character.SIZE + " bits  " + (int) Character.MIN_VALUE + " to " + (int) Character.MAX_VALUE);
        System.out.println("Defaults: " + b + " " + s + " " + i + " " + l + " " + f + " " + d + " [" + (int) c + "] " + bool);
    }
}

Output

byte    8 bits  -128 to 127
short   16 bits  -32768 to 32767
int     32 bits  -2147483648 to 2147483647
long    64 bits  -9223372036854775808 to 9223372036854775807
float   32 bits  max 3.4028235E38
double  64 bits  max 1.7976931348623157E308
char    16 bits  0 to 65535
Defaults: 0 0 0 0 0.0 0.0 [0] false

Note: default values only apply to fields (class variables). Local variables inside a method have no default — the compiler makes you assign them before use.

Advertisement

Primitive vs Non-Primitive Data Types

PrimitiveNon-primitive (reference)
Examplesint, double, boolean, charString, arrays, ArrayList, your own classes
StoresThe value itselfA reference (address) to an object
Can be null?NoYes
Has methods?NoYes, e.g. "abc".length()
Default (as a field)0, 0.0, false or '\u0000'null

Each primitive has a wrapper class — Integer, Double, Boolean… — used in collections like List<Integer>. Java converts between them automatically (autoboxing).

Non-Primitive Data Types in Java

Non-primitive (reference) data types are everything that isn't one of the 8 primitives: String, arrays, classes, interfaces, enums, records and collections such as List. A variable of these types stores a reference to an object, so it can be null and it has methods. All of them in one program (Java 21):

import java.util.ArrayList;
import java.util.List;

public class NonPrimitive {
    enum Browser { CHROME, FIREFOX }                      // enum
    record TestResult(String name, boolean passed) {}     // record (Java 16+)
    interface Reporter { void report(TestResult r); }     // interface

    static String notSet;                                 // reference fields default to null

    public static void main(String[] args) {
        String title = "Login";                           // String (a class)
        int[] timeouts = {5, 10, 30};                     // array
        List<Integer> retries = new ArrayList<>();        // collection of wrapper objects
        retries.add(2);                                   // autoboxing: int -> Integer
        TestResult r = new TestResult(title, true);       // object of your own type
        Reporter console = res -> System.out.println("Report: " + res);

        System.out.println("String length: " + title.length() + ", upper: " + title.toUpperCase());
        System.out.println("Array length: " + timeouts.length + ", first: " + timeouts[0]);
        System.out.println("List: " + retries + ", enum: " + Browser.FIREFOX);
        console.report(r);
        System.out.println("Default of a reference field: " + notSet);

        String a = new String("Login");
        System.out.println("a == title: " + (a == title) + ", a.equals(title): " + a.equals(title));
        try {
            System.out.println(notSet.length());
        } catch (NullPointerException e) {
            System.out.println("Calling a method on null -> NullPointerException");
        }
    }
}

Output

String length: 5, upper: LOGIN
Array length: 3, first: 5
List: [2], enum: FIREFOX
Report: TestResult[name=Login, passed=true]
Default of a reference field: null
a == title: false, a.equals(title): true
Calling a method on null -> NullPointerException

Two rules every tester needs: compare object contents with equals(), not == (which compares references), and check for null before calling a method — otherwise you get a NullPointerException.

Five Traps Every Tester Should Know

public class Traps {
    public static void main(String[] args) {
        int max = Integer.MAX_VALUE;
        System.out.println("1. int overflow: " + (max + 1));
        long safe = (long) max + 1;
        System.out.println("   with long:    " + safe);
        System.out.println("2. integer division 7 / 2 = " + (7 / 2) + ", 7 / 2.0 = " + (7 / 2.0));
        System.out.println("3. 0.1 + 0.2 = " + (0.1 + 0.2));
        char grade = 'A';
        System.out.println("4. 'A' + 1 = " + (grade + 1) + ", (char)('A' + 1) = " + (char) (grade + 1));
        double price = 19.99;
        int rounded = (int) price;
        System.out.println("5. (int) 19.99 = " + rounded + ", Math.round(19.99) = " + Math.round(price));
    }
}

Output

1. int overflow: -2147483648
   with long:    2147483648
2. integer division 7 / 2 = 3, 7 / 2.0 = 3.5
3. 0.1 + 0.2 = 0.30000000000000004
4. 'A' + 1 = 66, (char)('A' + 1) = B
5. (int) 19.99 = 19, Math.round(19.99) = 20
  1. Overflow: going past int's maximum silently wraps to a negative number — no error. Use long for large totals.
  2. Integer division drops the decimal part: 7 / 2 is 3. Make one side a double to get 3.5.
  3. Floating-point precision: 0.1 + 0.2 is not exactly 0.3. Never compare prices with ==; use BigDecimal or compare with a small tolerance.
  4. char is a number: 'A' + 1 is 66 (the Unicode value). Cast back to char to get 'B'.
  5. Casting truncates: (int) 19.99 is 19, not 20. Use Math.round to round.

Common Mistakes

  1. Large whole numbers without L: long big = 3000000000; fails with error: integer number too large. Fix: 3000000000L.
  2. Decimals assigned to float without f: float rate = 2.5; fails with error: incompatible types: possible lossy conversion from double to float. Fix: 2.5f, or simply use double.
  3. Using == to compare double values such as totals in a shopping-cart test. Use BigDecimal or a tolerance.
  4. Thinking String is a primitive. It's a class — that's why it has methods and can be null.

Practice Exercises

  1. Print the result of Integer.MAX_VALUE + 1 and explain it.
  2. Write a method that returns the average of three int scores as a double without losing the decimal part.
  3. Verify a cart total: add 19.99 + 5.01 + 0.10 with double and with BigDecimal, and compare the results.

Key Takeaways

  • Java has exactly 8 primitive types; use int and double by default.
  • Overflow and integer division don't throw errors — they silently give wrong answers.
  • Never use double with == for money; use BigDecimal.

📚 Official documentation: dev.java: Primitive types · Java Language Specification: Primitive types

Frequently Asked Questions

How many primitive data types are there in Java?

Eight: byte, short, int, long, float, double, char and boolean.

Is String a primitive data type in Java?

No. String is a class (a reference type). That is why it has methods like length() and can be null.

What is the default value of int in Java?

0 — for fields. Local variables have no default value and must be assigned before use.

What is the size of char in Java?

16 bits. A char holds one UTF-16 code unit, from 0 to 65,535.

Which data type should I use for money?

Use BigDecimal. double cannot represent most decimal fractions exactly, so 0.1 + 0.2 gives 0.30000000000000004.