Java: Data Types, Operators & Control Flow

Nagesh Chauhan 26 Jun 2026 7 min read
0
Data types define the kind of data that can be stored in variables, the memory allocated for that data, and the operations that can be performed on it. Java is a strongly typed language, which means every variable and expression has a well-defined type that is verified at compile time.

Data Types

Java categorizes data types into two groups:

1. Primitive Types
2. Reference Types

Primitive types directly store values, whereas reference types store references to objects located in heap memory.

Primitive Data Types

Java defines eight primitive data types.
Type Size Default Value Range
byte 8 bits 0 -128 to 127
short 16 bits 0 -32,768 to 32,767
int 32 bits 0 -231 to 231-1
long 64 bits 0L -263 to 263-1
float 32 bits 0.0f IEEE 754
double 64 bits 0.0d IEEE 754
char 16 bits '\u0000' Unicode character
boolean JVM dependent false true or false
Primitive types are stored directly in variables and do not contain methods.
int age = 30;
double salary = 75000.50;
char grade = 'A';
boolean active = true;

Reference Types

Reference types include classes, interfaces, arrays, enums, records, and annotations.
String name = "John";
Employee employee = new Employee();
List<String> cities = new ArrayList<>();
A reference variable stores the memory address of an object, not the object itself. Reference variables can hold null.
Employee employee = null;
Dereferencing a null reference throws NullPointerException.

Primitive vs Reference Types

Primitive types have fixed memory size, store values directly, cannot be null, and are generally faster because no object allocation is required.

Reference types store object references, can be null, support inheritance and polymorphism, and require heap allocation for objects.

Numeric Literals

Java supports decimal, binary, octal, and hexadecimal literals.
int decimal = 100;
int binary = 0b1100100;
int octal = 0144;
int hexadecimal = 0x64;
Underscores improve readability.
long population = 8_500_000_000L;

Floating-Point Literals

Floating-point literals are double by default.
double price = 99.99;
float discount = 10.5f;
Using a float literal without the f suffix results in a compilation error.

Character Literals

Characters use single quotes and represent Unicode characters.
char letter = 'A';
char symbol = '$';
char unicode = '\u20B9';

Escape Sequences

Java supports several escape characters.
System.out.println("Hello\nWorld");
System.out.println("Java\tProgramming");
System.out.println("\"Quoted\"");
System.out.println("\\");
Common escape sequences include: \n New line, \t Tab, " Double quote, ' Single quote, \ Backslash.

Variables

Variables are classified into three categories.

1. Local Variables are declared inside methods and must be initialized before use.
2. Instance Variables belong to objects and receive default values.
3. Static Variables belong to the class and are shared by all objects.
class Employee {

    static String company = "ABC";
    String name;

    void display() {
        int age = 30;

        System.out.println(company);
        System.out.println(name);
        System.out.println(age);
    }
}

Default Values

Instance and static variables receive default values.
int number = 0;
boolean active = false;
double salary = 0.0;
char grade = '\u0000';
Object reference = null;
Local variables never receive default values.

Type Conversion

Java supports implicit widening and explicit narrowing.

1. Widening occurs automatically.
int number = 100;
long value = number;
double salary = value;
2. Narrowing requires explicit casting.
double price = 99.99;
int value = (int) price;
Output:
99
Narrowing may lose precision.

Type Casting

Reference types can also be cast.
Animal animal = new Dog();
Dog dog = (Dog) animal;
Invalid casts throw ClassCastException.

Type Inference

Java supports local variable type inference using var.
var name = "John";
var numbers = List.of(1, 2, 3);
The compiler infers the variable type during compilation. var can only be used for local variables.

Operators

Java operators are categorized as follows.

- Arithmetic
- Unary
- Assignment
- Relational
- Logical
- Bitwise
- Shift
- Conditional
- Instanceof

Arithmetic Operators

Arithmetic operators perform mathematical operations.
int a = 10;
int b = 3;

System.out.println(a + b);
System.out.println(a - b);
System.out.println(a * b);
System.out.println(a / b);
System.out.println(a % b);
Integer division discards the fractional part.
System.out.println(10 / 3);
Output:
3

Unary Operators

Unary operators work on a single operand.
int x = 5;
++x;
--x;
+x;
-x;
!true;

Increment and Decrement

Pre-increment modifies the value before evaluation.
int x = 5;
System.out.println(++x);
Output:
6
Post-increment evaluates first and increments afterward.
int x = 5;
System.out.println(x++);
System.out.println(x);
Output:
5
6

Assignment Operators

int x = 10;
x += 5;
x -= 2;
x *= 3;
x /= 2;
x %= 4;
Compound assignment performs the operation and assignment together.

Relational Operators

Relational operators compare values.
int a = 10;
int b = 20;

System.out.println(a > b);
System.out.println(a < b);
System.out.println(a >= b);
System.out.println(a <= b);
System.out.println(a == b);
System.out.println(a != b);
The result is always a boolean value.

Logical Operators

Logical operators combine boolean expressions.
boolean a = true;
boolean b = false;
System.out.println(a && b);
System.out.println(a || b);
System.out.println(!a);
The operators && and || use short-circuit evaluation.
if (employee != null && employee.isActive()) {
}
The second expression executes only if required.

Bitwise Operators

Bitwise operators operate directly on bits.
int a = 5;
int b = 3;
a & b;
a | b;
a ^ b;
~a;
These operators are commonly used in low-level programming and performance-sensitive applications.

Shift Operators

Shift operators move bits left or right.
int number = 8;
number << 1;
number >> 1;
number >>> 1;
<< Left shift
>> Signed right shift
>>> Unsigned right shift

Ternary Operator

The conditional operator provides a concise alternative to simple if-else statements.
String result = age >= 18 ? "Adult" : "Minor";
The ternary operator returns a value and should be used only when it improves readability.

Operator Precedence

Java evaluates expressions according to predefined operator precedence. Parentheses should be used whenever precedence is not immediately obvious.
int result = (a + b) * c;
Readable code is preferred over relying on operator precedence.

Conditional Statements

if Statement

The if statement executes code when a condition is true.
if (age >= 18) {
    System.out.println("Adult");
}

if-else Statement

if (marks >= 40) {
    System.out.println("Pass");
} else {
    System.out.println("Fail");
}

else-if Ladder

if (marks >= 90) {
    System.out.println("A");
} else if (marks >= 80) {
    System.out.println("B");
} else {
    System.out.println("C");
}
Conditions are evaluated sequentially until one matches.

switch Statement

Modern Java supports both traditional and enhanced switch expressions. Traditional switch:
switch (day) {

    case 1:
        System.out.println("Monday");
        break;

    default:
        System.out.println("Invalid");
}
Enhanced switch:
String dayName = switch (day) {

    case 1 -> "Monday";
    case 2 -> "Tuesday";
    default -> "Invalid";
};
Enhanced switch eliminates fall-through and improves readability.

Loops

for Loop

The for loop is used when the number of iterations is known.
for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}

Enhanced for Loop

The enhanced for loop iterates over arrays and collections.
for (String city : cities) {
    System.out.println(city);
}
It cannot modify the underlying collection structure.

while Loop

The while loop executes while the condition remains true.
while (count > 0) {
    count--;
}
Use while when the number of iterations is unknown.

do-while Loop

The do-while loop always executes at least once.
do {
    System.out.println(count);
} while (count > 0);

break Statement

The break statement immediately terminates the nearest loop or switch.
for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;
    }
}

continue Statement

The continue statement skips the current iteration.
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        continue;
    }
    System.out.println(i);
}

Labeled break and continue

Java supports labeled statements for nested loops.
outer:
for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        if (j == 2) {
            break outer;
        }
    }
}
Labeled statements should be used sparingly because they often reduce readability.

Pattern Matching in switch

Modern Java extends switch to support pattern matching.
Object value = "Java";

switch (value) {
    case String s -> System.out.println(s.length());
    case Integer i -> System.out.println(i * 2);
    default -> System.out.println("Unknown");
}
Pattern matching eliminates many explicit casts and instanceof checks.

Expression Statements

Java expressions can produce values, while statements perform actions.
int x = 10 + 20;
System.out.println(x);
Understanding this distinction helps when working with lambda expressions, switch expressions, and functional APIs.

Final Notes

Java provides a rich type system and a comprehensive set of operators and control flow constructs.

Choosing appropriate data types, avoiding unnecessary type conversions, understanding operator precedence, using short-circuit logical operators, preferring enhanced switch expressions, and selecting the correct looping construct improve readability, correctness, and performance.
Nagesh Chauhan

Nagesh Chauhan

Principal Engineer | Java ยท Spring Boot ยท Python ยท Microservices ยท AI/ML

Principal Engineer with 14+ years of experience in designing scalable systems using Java, Spring Boot, and Python. Specialized in microservices architecture, system design, and machine learning.

Share this Article

๐Ÿ’ฌ Comments

Join the Discussion