☕ Java

Java Operators — Types, Syntax, Examples & Best Practices

Everything you need to know about Java Operators — arithmetic, relational, logical, bitwise, assignment, unary, ternary, instanceof, operator precedence, short-circuit evaluation, anti-patterns, and real-world production code examples.

📅

Last Updated

March 2026

⏱️

Read Time

22 min

🎯

Level

Beginner

🏷️

Chapter

7 of 35

What are Operators in Java?

Operators are special symbols or keywords in Java that perform operations on one or more operands (values or variables) and produce a result. Every expression in Java — from simple arithmetic to complex conditional logic — is built using operators. For example, in int sum = a + b, the + is the operator and a, b are operands.

Java provides a rich set of operators organized into 8 major categories. Understanding operators deeply is foundational — they appear in every Java program and are frequently tested in interviews. Mastering operator precedence, short-circuit evaluation, and the subtle differences between similar operators (like == vs .equals(), or & vs &&) separates good Java developers from great ones.

Operators can be classified by the number of operands they work on: Unary operators work on one operand (++x), Binary operators work on two operands (a + b), and the Ternary operator works on three operands (condition ? val1 : val2). Java is the only operator that is ternary.

Types of Operators in Java

Java operators are grouped by the type of operation they perform. Each category has distinct rules, use cases, and pitfalls. The table below gives a quick overview before we dive into each one in detail.

CategoryOperatorsReturn TypeWorks OnExample
Arithmetic+ - * / %NumericNumeric typesa + b, x % 3
Relational== != > < >= <=booleanPrimitives & objectsa > b, x == y
Logical&& || !booleanboolean expressionsa && b, !flag
Assignment= += -= *= /= %= &= |= etc.variesAny variablex += 5, y *= 2
Unary++ -- + - !variesSingle operand++x, -a, !flag
Bitwise& | ^ ~int/longInteger typesa & b, x ^ y
Shift<< >> >>>int/longInteger typesx << 2, n >> 1
Ternary?:variesAny typea > b ? a : b
instanceofinstanceofbooleanObject referencesobj instanceof Dog

Arithmetic Operators

Arithmetic operators perform standard mathematical operations. Java supports five arithmetic operators: addition (+), subtraction (-), multiplication (*), division (/), and modulus (%). The + operator also works as string concatenation when used with String operands — this is one of the most common sources of subtle bugs in Java.

📌
Integer Division vs Float Division

In Java, dividing two integers always produces an integer result (truncates toward zero, not rounded). 7 / 2 = 3, not 3.5. To get a decimal result, at least one operand must be a float or double: 7.0 / 2 = 3.5, or (double) 7 / 2 = 3.5. This is the #1 arithmetic bug in beginner Java code — always cast to double when decimal precision is needed.

📌
Modulus (%) Operator

The modulus operator returns the remainder of division. 10 % 3 = 1, 15 % 5 = 0. Works with floating-point numbers too: 10.5 % 3.2 = 0.9 (approx). With negative numbers, the result takes the sign of the dividend (left operand): -7 % 3 = -1. Common uses: checking even/odd (n % 2 == 0), cycling through indexes (index % arrayLength), time calculations (seconds % 60).

📌
String Concatenation with +

When + involves a String operand, it performs concatenation instead of addition. 'Hello' + ' World' = 'Hello World'. 'Value: ' + 5 = 'Value: 5'. But: 1 + 2 + ' apples' = '3 apples' (left-to-right: 1+2=3, then 3+' apples'). Vs: 'apples: ' + 1 + 2 = 'apples: 12' (String+int concatenates). Use parentheses to control evaluation order.

☕ JavaArithmeticOperators.java
public class ArithmeticOperators {
    public static void main(String[] args) {

        int a = 15, b = 4;

        // Basic arithmetic
        System.out.println(a + b);   // 19 — addition
        System.out.println(a - b);   // 11 — subtraction
        System.out.println(a * b);   // 60 — multiplication
        System.out.println(a / b);   // 3  — integer division (NOT 3.75!)
        System.out.println(a % b);   // 3  — remainder (15 = 4*3 + 3)

        // ✅ Correct: float division
        System.out.println((double) a / b);  // 3.75
        System.out.println(a / 4.0);         // 3.75

        // ✅ String concatenation vs addition
        System.out.println("Sum: " + a + b);    // 'Sum: 154' — concatenation!
        System.out.println("Sum: " + (a + b));  // 'Sum: 19'  — add first
        System.out.println(a + b + " is sum");  // '19 is sum' — adds first (no String left)

        // ✅ Modulus use cases
        System.out.println(10 % 2 == 0 ? "Even" : "Odd"); // Even
        System.out.println(7 % 2 == 0 ? "Even" : "Odd");  // Odd

        // ✅ ArithmeticException: division by zero (integer only)
        // int x = 5 / 0;     // ❌ Throws ArithmeticException: / by zero
        double y = 5.0 / 0;   // ✅ Returns Infinity (no exception for double)
        double z = 0.0 / 0;   // ✅ Returns NaN (Not a Number)
        System.out.println(y); // Infinity
        System.out.println(z); // NaN
    }
}

Relational (Comparison) Operators

Relational operators compare two values and always return a boolean result (true or false). They are the foundation of all conditional logic in Java — used in if, while, for, and ternary expressions. Java provides six relational operators: ==, !=, >, <, >=, and <=.

☕ JavaRelationalOperators.java
public class RelationalOperators {
    public static void main(String[] args) {

        int x = 10, y = 20;

        System.out.println(x == y);  // false — equal to
        System.out.println(x != y);  // true  — not equal to
        System.out.println(x > y);   // false — greater than
        System.out.println(x < y);   // true  — less than
        System.out.println(x >= 10); // true  — greater than or equal
        System.out.println(x <= 10); // true  — less than or equal

        // ⚠️ CRITICAL: == on objects compares REFERENCES, not content
        String s1 = new String("Java");
        String s2 = new String("Java");
        System.out.println(s1 == s2);       // false — different objects!
        System.out.println(s1.equals(s2));  // true  — same content ✅

        // ⚠️ String pool: literals may share reference — don't rely on this
        String s3 = "Java";
        String s4 = "Java";
        System.out.println(s3 == s4);  // true (pool) — but NEVER use == for Strings

        // ✅ For primitives, == compares values
        int a = 100, b = 100;
        System.out.println(a == b);  // true — primitives: value comparison

        // ✅ Wrapper Integer: == only reliable for -128 to 127 (cache range)
        Integer i1 = 100, i2 = 100;
        System.out.println(i1 == i2);      // true  (cached)
        Integer i3 = 200, i4 = 200;
        System.out.println(i3 == i4);      // false (outside cache — new objects!)
        System.out.println(i3.equals(i4)); // true  ✅ always use .equals() for wrappers
    }
}

Logical Operators

Logical operators combine or invert boolean expressions and always return a boolean result. Java provides three logical operators: && (AND), || (OR), and ! (NOT). The AND and OR operators use short-circuit evaluation — one of the most important Java evaluation behaviors to understand for writing safe, efficient code.

🔑
&& (Logical AND) — Short-Circuit

Returns true only if BOTH operands are true. Short-circuits: if the left operand is false, the right operand is never evaluated. Use this for safe null checks: if (obj != null && obj.getValue() > 0) — if obj is null, obj.getValue() is never called. Prevents NullPointerException. Both operands MUST be boolean.

🔑
|| (Logical OR) — Short-Circuit

Returns true if AT LEAST ONE operand is true. Short-circuits: if the left operand is true, the right operand is never evaluated. Use for default value patterns: if (name != null || (name = getDefault()) != null). The right side only runs when needed. Performance tip: put the more likely true condition on the left for OR, and the more likely false condition on the left for AND.

🔑
& and | (Non-Short-Circuit)

The bitwise & and | operators, when used with boolean operands, behave like && and || but WITHOUT short-circuit evaluation — BOTH sides are always evaluated. Rarely used for logical operations. Use case: when the right-side expression MUST be evaluated for its side effects (e.g., incrementing a counter). In general, prefer && and || for boolean logic.

☕ JavaLogicalOperators.java
public class LogicalOperators {
    public static void main(String[] args) {

        boolean a = true, b = false;

        // Basic logical operations
        System.out.println(a && b);  // false — AND: both must be true
        System.out.println(a || b);  // true  — OR: at least one true
        System.out.println(!a);       // false — NOT: inverts
        System.out.println(!b);       // true

        // ✅ Short-circuit AND — prevents NullPointerException
        String str = null;
        if (str != null && str.length() > 0) {  // str.length() never called if str == null
            System.out.println("Non-empty string");
        } else {
            System.out.println("String is null or empty"); // Safe!
        }

        // ✅ Short-circuit OR — right side only runs if left is false
        int count = 0;
        boolean result = (count > 0) || (++count > 0);
        System.out.println(count);  // 1 — right side WAS evaluated (left was false)

        int count2 = 1;
        boolean result2 = (count2 > 0) || (++count2 > 0);
        System.out.println(count2); // 1 — right side NOT evaluated (left was true, short-circuit!)

        // ✅ Combining logical operators
        int age = 25;
        boolean hasId = true;
        boolean isMinor = age < 18;

        if (!isMinor && hasId) {
            System.out.println("Access granted");
        }

        // ✅ De Morgan's Laws — useful for simplifying conditions
        // !(a && b) == (!a || !b)
        // !(a || b) == (!a && !b)
        boolean x = true, y = false;
        System.out.println(!(x && y));      // true
        System.out.println(!x || !y);       // true — equivalent!
    }
}

Assignment Operators

Assignment operators assign values to variables. The basic assignment operator is =. Java also provides compound assignment operators that combine an arithmetic or bitwise operation with assignment in a single step. For example, x += 5 is shorthand for x = x + 5. Compound operators are more concise and also perform an implicit narrowing cast — an important detail when working with byte and short types.

☕ JavaAssignmentOperators.java
public class AssignmentOperators {
    public static void main(String[] args) {

        int x = 10;  // Basic assignment

        // ✅ Compound assignment operators
        x += 5;   System.out.println(x);  // 15 — x = x + 5
        x -= 3;   System.out.println(x);  // 12 — x = x - 3
        x *= 2;   System.out.println(x);  // 24 — x = x * 2
        x /= 4;   System.out.println(x);  // 6  — x = x / 4
        x %= 4;   System.out.println(x);  // 2  — x = x % 4

        // ✅ Bitwise compound assignment
        x &= 3;   System.out.println(x);  // 2  — x = x & 3
        x |= 5;   System.out.println(x);  // 7  — x = x | 5
        x ^= 2;   System.out.println(x);  // 5  — x = x ^ 2
        x <<= 1;  System.out.println(x);  // 10 — x = x << 1
        x >>= 1;  System.out.println(x);  // 5  — x = x >> 1

        // ✅ Implicit narrowing cast with compound assignment
        byte b = 10;
        // b = b + 5;    // ❌ Compile error: int cannot be converted to byte
        b += 5;          // ✅ Works! Compound += includes implicit (byte) cast
        System.out.println(b); // 15

        // ✅ Chained assignment
        int a, c, d;
        a = c = d = 100;  // All assigned 100 — right to left
        System.out.println(a + " " + c + " " + d); // 100 100 100

        // ✅ Assignment is itself an expression (returns assigned value)
        int val;
        if ((val = getValue()) > 0) {  // Assigns AND checks in one step
            System.out.println("Positive: " + val);
        }
    }

    static int getValue() { return 42; }
}

Unary Operators

Unary operators operate on a single operand. Java provides five unary operators: + (unary plus), - (unary minus/negation), ++ (increment), -- (decrement), and ! (logical NOT). The increment and decrement operators have two forms — prefix (++x) and postfix (x++) — which behave differently inside expressions.

📌
Prefix vs Postfix Increment/Decrement

Prefix (++x or --x): modifies the variable FIRST, then returns the NEW value. Postfix (x++ or x--): returns the CURRENT (original) value first, THEN modifies the variable. As a standalone statement (e.g., i++ on its own line), both are identical. The difference only matters when the expression value is used — inside assignments, method calls, array indexing, or larger expressions.

⚠️
Increment Inside Expressions — Be Careful

Avoid using ++ or -- inside complex expressions — the result is hard to predict and varies by evaluation order. Example: int x = 5; int y = x++ + ++x; — y = 12 (tricky!). Best practice: use increment operators only as standalone statements (i++ on its own line), not embedded inside larger expressions. This prevents confusion and makes intent clear.

☕ JavaUnaryOperators.java
public class UnaryOperators {
    public static void main(String[] args) {

        int a = 5;

        // Unary plus and minus
        System.out.println(+a);   // 5  — unary plus (no change for positive)
        System.out.println(-a);   // -5 — negation

        // ✅ Logical NOT
        boolean flag = true;
        System.out.println(!flag);   // false
        System.out.println(!!flag);  // true  — double negation

        // ✅ Prefix vs Postfix — the key difference
        int x = 10;
        System.out.println(x++);  // 10 — returns CURRENT value, THEN increments
        System.out.println(x);    // 11 — x has been incremented

        int y = 10;
        System.out.println(++y);  // 11 — increments FIRST, then returns NEW value
        System.out.println(y);    // 11

        // ✅ Postfix in a loop (most common use)
        for (int i = 0; i < 3; i++) {  // i++ is fine here as standalone
            System.out.print(i + " ");  // 0 1 2
        }
        System.out.println();

        // ⚠️ Tricky: prefix in assignment
        int n = 5;
        int result = ++n * 2;  // n becomes 6 first, then 6 * 2 = 12
        System.out.println(result); // 12
        System.out.println(n);      // 6

        // ⚠️ Even trickier — avoid this in real code
        int m = 5;
        int tricky = m++ + ++m;  // m++ returns 5 (m→6), ++m returns 7 (m→7): 5+7=12
        System.out.println(tricky); // 12 — but this style is unreadable, avoid it!
    }
}

Bitwise Operators

Bitwise operators operate directly on the binary representation (individual bits) of integer types (int, long, byte, short). They are used in low-level programming, performance-sensitive code, permission systems, flags, encryption, and embedded systems. Java provides four bitwise operators: & (AND), | (OR), ^ (XOR), and ~ (bitwise complement/NOT).

🔧
& (Bitwise AND)

Sets a bit to 1 only if BOTH corresponding bits are 1. Otherwise 0. Example: 12 & 10 = 8 (1100 & 1010 = 1000). Common use: masking (isolating specific bits). Check if a bit is set: if ((flags & 0x01) != 0). Also used to check even/odd: n & 1 == 0 means even (faster than n % 2).

🔧
| (Bitwise OR)

Sets a bit to 1 if EITHER corresponding bit is 1. Example: 12 | 10 = 14 (1100 | 1010 = 1110). Common use: setting specific bits (flags). Turn on a bit: flags |= 0x04. Used in permission systems to grant rights: permissions |= READ_PERMISSION.

🔧
^ (Bitwise XOR) and ~ (Complement)

XOR (^): sets bit to 1 if bits DIFFER, 0 if same. 12 ^ 10 = 6 (1100 ^ 1010 = 0110). Used to toggle bits and in encryption/hashing. ~ (complement): inverts ALL bits. ~5 = -6 (in two's complement). Rule: ~n = -(n+1). Use for toggling flags: flags ^= 0x02.

☕ JavaBitwiseOperators.java
public class BitwiseOperators {

    // ✅ Real-world: permission flags using bitwise operators
    static final int READ    = 0b001;  // 1
    static final int WRITE   = 0b010;  // 2
    static final int EXECUTE = 0b100;  // 4

    public static void main(String[] args) {

        int a = 12; // Binary: 1100
        int b = 10; // Binary: 1010

        System.out.println(a & b);  // 8  — 1100 & 1010 = 1000
        System.out.println(a | b);  // 14 — 1100 | 1010 = 1110
        System.out.println(a ^ b);  // 6  — 1100 ^ 1010 = 0110
        System.out.println(~a);     // -13 — inverts all bits of 12

        // ✅ Permission system using bitwise OR to grant, AND to check
        int userPermissions = READ | WRITE;  // 001 | 010 = 011 (3)

        boolean canRead    = (userPermissions & READ)    != 0;  // true
        boolean canWrite   = (userPermissions & WRITE)   != 0;  // true
        boolean canExecute = (userPermissions & EXECUTE) != 0;  // false

        System.out.println("Read: " + canRead);      // true
        System.out.println("Write: " + canWrite);    // true
        System.out.println("Execute: " + canExecute); // false

        // ✅ Grant execute permission
        userPermissions |= EXECUTE;
        System.out.println("Execute after grant: " + ((userPermissions & EXECUTE) != 0)); // true

        // ✅ Revoke write permission
        userPermissions &= ~WRITE;
        System.out.println("Write after revoke: " + ((userPermissions & WRITE) != 0));  // false

        // ✅ Toggle read permission with XOR
        userPermissions ^= READ;
        System.out.println("Read after toggle: " + ((userPermissions & READ) != 0)); // false (was true)

        // ✅ Fast even/odd check with bitwise AND
        for (int i = 0; i <= 5; i++) {
            System.out.println(i + " is " + ((i & 1) == 0 ? "even" : "odd"));
        }
    }
}

Shift Operators

Shift operators move the bits of an integer value left or right by a specified number of positions. Java provides three shift operators: << (left shift), >> (signed/arithmetic right shift), and >>> (unsigned/logical right shift). Shift operators are commonly used in performance optimization (powers of 2), data packing, hashing algorithms, and low-level system code.

🔧
<< (Left Shift)

Shifts bits to the left, filling vacated positions on the right with 0s. Each left shift by 1 is equivalent to multiplying by 2. n << k = n * 2^k. Example: 5 << 1 = 10, 5 << 2 = 20. Bits shifted beyond the 32/64 bit boundary are lost. Commonly used for fast multiplication by powers of 2 and bit packing.

🔧
>> (Signed Right Shift)

Shifts bits to the right, filling vacated positions on the left with the sign bit (0 for positive, 1 for negative). Preserves the sign. Each right shift by 1 is equivalent to integer division by 2 (floor for negatives). n >> k = n / 2^k. Example: 20 >> 1 = 10, -20 >> 1 = -10. Safe for all signed integers.

🔧
>>> (Unsigned Right Shift)

Shifts bits to the right, ALWAYS filling vacated positions with 0 — regardless of sign. Does not preserve sign bit. For positive numbers, same as >>. For negative numbers, result is a large positive number. Used in hashing (HashMap uses >>> 16 for hash spreading) and graphics/color manipulation where you want raw bit manipulation without sign extension.

☕ JavaShiftOperators.java
public class ShiftOperators {
    public static void main(String[] args) {

        int n = 8; // Binary: 00001000

        // ✅ Left shift — multiply by power of 2
        System.out.println(n << 1);  // 16  — 8 * 2^1
        System.out.println(n << 2);  // 32  — 8 * 2^2
        System.out.println(n << 3);  // 64  — 8 * 2^3

        // ✅ Signed right shift — divide by power of 2
        System.out.println(64 >> 1); // 32  — 64 / 2^1
        System.out.println(64 >> 2); // 16  — 64 / 2^2
        System.out.println(64 >> 3); // 8   — 64 / 2^3

        // ✅ Signed right shift preserves sign
        System.out.println(-64 >> 2); // -16 — sign preserved

        // ✅ Unsigned right shift — sign bit filled with 0
        System.out.println(-1 >>> 1);  // 2147483647 (Integer.MAX_VALUE) — sign gone
        System.out.println(-64 >>> 2); // large positive number

        // ✅ Real-world: fast power of 2 check using bit manipulation
        int num = 64;
        boolean isPowerOfTwo = (num > 0) && (num & (num - 1)) == 0;
        System.out.println(num + " is power of 2: " + isPowerOfTwo); // true

        // ✅ HashMap-style hash spreading (from Java source)
        int hash = 12345678;
        int spread = hash ^ (hash >>> 16);  // XOR with upper 16 bits
        System.out.println("Spread hash: " + spread);

        // ✅ Extract RGB color components from packed int
        int color = 0xFF5733AA; // packed ARGB
        int alpha = (color >> 24) & 0xFF;
        int red   = (color >> 16) & 0xFF;
        int green = (color >> 8)  & 0xFF;
        int blue  =  color        & 0xFF;
        System.out.printf("A=%d R=%d G=%d B=%d%n", alpha, red, green, blue);
    }
}

Ternary Operator (?:)

The ternary operator (?:) is Java's only operator that takes three operands. It provides a compact way to write a simple if-else expression in a single line. Syntax: condition ? valueIfTrue : valueIfFalse. The condition must evaluate to a boolean, and both branches must return compatible types. The ternary operator is an expression (returns a value) unlike an if-else statement — so it can be used directly in assignments, method arguments, and string concatenation.

☕ JavaTernaryOperator.java
public class TernaryOperator {
    public static void main(String[] args) {

        int a = 15, b = 20;

        // ✅ Basic ternary — compact if-else
        int max = (a > b) ? a : b;
        System.out.println("Max: " + max); // 20

        int min = (a < b) ? a : b;
        System.out.println("Min: " + min); // 15

        // ✅ Ternary in string concatenation
        int score = 75;
        System.out.println("Result: " + (score >= 60 ? "Pass" : "Fail")); // Pass

        // ✅ Ternary as method argument
        printStatus(score >= 60 ? "Pass" : "Fail");

        // ✅ Null check pattern
        String name = null;
        String displayName = (name != null) ? name : "Guest";
        System.out.println(displayName); // Guest

        // ✅ Chained ternary (use sparingly — readability drops fast)
        int marks = 85;
        String grade = (marks >= 90) ? "A" :
                       (marks >= 80) ? "B" :
                       (marks >= 70) ? "C" :
                       (marks >= 60) ? "D" : "F";
        System.out.println("Grade: " + grade); // B

        // ⚠️ Bad practice: ternary with side effects — avoid
        int count = 0;
        // int x = (count++ > 0) ? count++ : count--;  // Confusing — use if-else instead
    }

    static void printStatus(String status) {
        System.out.println("Status: " + status);
    }
}

instanceof Operator

The instanceof operator checks whether an object is an instance of a specific class, subclass, or interface — returning a boolean. It is commonly used before downcasting to prevent ClassCastException. Java 16 introduced pattern matching for instanceof, which combines the check and cast in a single step — eliminating boilerplate and improving readability.

☕ JavaInstanceofOperator.java
class Animal { }
class Dog extends Animal {
    public void fetch() { System.out.println("Fetching!"); }
}
class Cat extends Animal {
    public void purr() { System.out.println("Purring!"); }
}

public class InstanceofOperator {
    public static void main(String[] args) {

        Animal a1 = new Dog();
        Animal a2 = new Cat();
        Animal a3 = null;

        // ✅ Basic instanceof check
        System.out.println(a1 instanceof Animal); // true  — Dog IS-A Animal
        System.out.println(a1 instanceof Dog);    // true  — actual type is Dog
        System.out.println(a1 instanceof Cat);    // false — Dog is NOT a Cat
        System.out.println(a3 instanceof Animal); // false — null is never instanceof anything

        // ✅ Traditional usage — check then cast
        if (a1 instanceof Dog) {
            Dog d = (Dog) a1;   // Safe cast after instanceof check
            d.fetch();
        }

        // ✅ Java 16+ Pattern Matching — check AND cast in one step
        if (a1 instanceof Dog dog) {   // 'dog' is automatically cast and in scope
            dog.fetch();               // No explicit (Dog) cast needed!
        }

        if (a2 instanceof Cat cat) {
            cat.purr();
        }

        // ✅ Pattern matching in a loop (polymorphic processing)
        Animal[] animals = { new Dog(), new Cat(), new Dog() };
        for (Animal animal : animals) {
            if (animal instanceof Dog d) {
                d.fetch();
            } else if (animal instanceof Cat c) {
                c.purr();
            }
        }

        // ✅ instanceof with interfaces
        java.util.List<String> list = new java.util.ArrayList<>();
        System.out.println(list instanceof java.util.List);       // true
        System.out.println(list instanceof java.util.Collection); // true
        System.out.println(list instanceof java.util.Iterable);   // true
    }
}

Operator Precedence Table

Operator precedence determines which operator is evaluated first when multiple operators appear in the same expression. Operators with higher precedence bind more tightly to their operands. When operators have equal precedence, associativity determines direction: most operators are left-to-right, but assignment and unary are right-to-left. Best practice: always use parentheses to make intent explicit instead of relying on precedence rules.

PrecedenceOperatorsAssociativityDescription
1 (Highest)() [] . x++ x--Left to RightParentheses, array access, member access, postfix
2+x -x ++x --x ~ !Right to LeftUnary plus/minus, prefix increment, bitwise NOT, logical NOT
3* / %Left to RightMultiplicative
4+ -Left to RightAdditive, string concatenation
5<< >> >>>Left to RightShift operators
6< > <= >= instanceofLeft to RightRelational, type comparison
7== !=Left to RightEquality
8&Left to RightBitwise AND
9^Left to RightBitwise XOR
10|Left to RightBitwise OR
11&&Left to RightLogical AND (short-circuit)
12||Left to RightLogical OR (short-circuit)
13?:Right to LeftTernary
14 (Lowest)= += -= *= /= %= etc.Right to LeftAssignment operators
☕ JavaOperatorPrecedence.java
public class OperatorPrecedence {
    public static void main(String[] args) {

        // * has higher precedence than +
        int a = 2 + 3 * 4;           // 2 + 12 = 14 (NOT 20)
        System.out.println(a);        // 14

        // Parentheses override precedence
        int b = (2 + 3) * 4;          // 5 * 4 = 20
        System.out.println(b);        // 20

        // Relational before equality
        boolean c = 5 > 3 == true;    // (5 > 3) == true → true == true → true
        System.out.println(c);        // true

        // && has higher precedence than ||
        boolean d = true || false && false;  // true || (false && false) → true || false → true
        System.out.println(d); // true

        boolean e = (true || false) && false; // true && false → false
        System.out.println(e); // false

        // Assignment is right-to-left
        int x, y, z;
        x = y = z = 5;  // z=5 first, then y=5, then x=5
        System.out.println(x + " " + y + " " + z); // 5 5 5

        // Tricky: + and string concatenation
        System.out.println(1 + 2 + "3");   // '33' — left to right: 1+2=3, then 3+"3"
        System.out.println("1" + 2 + 3);   // '123' — left to right: "1"+2="12", then "12"+3
        System.out.println("1" + (2 + 3)); // '15' — parentheses: 2+3=5, then "1"+5
    }
}

Common Mistakes & Pitfalls — Bugs That Fool Everyone

These are the most common operator-related mistakes in Java code — from beginners and occasionally from experienced developers who mix up subtle rules.

☕ JavaOperatorMistakes.java
// ❌ MISTAKE 1: Integer division when float result expected
int total = 7, count = 2;
double avg = total / count;  // 3.0 — NOT 3.5!
// ✅ Fix:
double avgFixed = (double) total / count;  // 3.5

// ❌ MISTAKE 2: Using == for String comparison
String s1 = new String("hello");
String s2 = new String("hello");
if (s1 == s2) { ... }         // Always false for new String()
// ✅ Fix:
if (s1.equals(s2)) { ... }    // Correct: compare content

// ❌ MISTAKE 3: Confusing = (assignment) with == (comparison)
int x = 5;
// if (x = 10) { ... }    // Compile error in Java (unlike C) — but still easy to misread
if (x == 10) { ... }      // Correct comparison

// ❌ MISTAKE 4: Not accounting for operator precedence
boolean result = 2 + 3 > 4 && 5 < 10 || 1 == 1;
// Actual: ((2+3) > 4) && (5 < 10) || (1 == 1) → true && true || true → true
// ✅ Fix: use parentheses for clarity
boolean resultClear = ((2 + 3) > 4) && (5 < 10) || (1 == 1);

// ❌ MISTAKE 5: Modulus with negative numbers
System.out.println(-7 % 3);   // -1 (NOT 2) — sign follows dividend in Java
// ✅ Fix for always-positive remainder:
System.out.println(Math.floorMod(-7, 3)); // 2 — always positive

// ❌ MISTAKE 6: Overflow in integer arithmetic (silent bug)
int maxVal = Integer.MAX_VALUE;
System.out.println(maxVal + 1);  // -2147483648 — integer overflow, no exception!
// ✅ Fix: use long or check before operation
long safeResult = (long) maxVal + 1;  // 2147483648 — correct

// ❌ MISTAKE 7: Division by zero for integers (throws exception)
// int bad = 10 / 0;   // ArithmeticException: / by zero
// ✅ Always check divisor before dividing
int divisor = 0;
if (divisor != 0) { int safe = 10 / divisor; }

Bad Practices & Anti-Patterns — What Senior Developers Reject

These anti-patterns represent common misuses of operators in professional Java code. Each one reduces readability, introduces bugs, or signals misunderstanding of the language.

🚫
Using == for Object Equality

Using == to compare Strings, Integers, or custom objects checks reference identity, not value. String a = new String('x'); String b = new String('x'); a == b is false. Always use .equals() for objects. For null-safe comparison, use Objects.equals(a, b) which handles null without NullPointerException. This is the single most common Java bug in beginner code.

🚫
Deeply Nested Ternary Chains

Chaining more than 2 levels of ternary operators creates code that is nearly impossible to read, debug, or modify. Replace with a clear if-else-if ladder or a switch expression. The ternary operator exists for simple one-liners — using it as a replacement for complex conditional logic is an anti-pattern that most code review teams will reject.

🚫
Relying on Implicit Operator Precedence

Writing expressions like 'a + b > c && d || e' without parentheses forces every reader to mentally recall the precedence table. This is error-prone and slows code review. Always use parentheses to make complex expressions unambiguous: '((a + b) > c) && (d || e)'. Parentheses are free — unambiguous code is priceless.

🚫
Increment Operators in Complex Expressions

Embedding ++ or -- inside larger expressions — array[i++] = j-- or method(i++, ++j) — creates subtle evaluation-order bugs and reduces readability. Use increment operators as standalone statements only (i++ or ++i on their own line). Let the next line use the updated value. This is the style enforced by most major Java style guides and static analysis tools.

🚫
Ignoring Integer Overflow

Java silently wraps integer values on overflow without throwing any exception. int x = Integer.MAX_VALUE + 1 = -2147483648 — no warning, no error. In financial calculations, counters, or array index arithmetic, this causes catastrophic silent bugs. Use long for large values, Math.addExact() / multiplyExact() for overflow detection, or BigInteger for arbitrary precision.

🚫
Using Bitwise Operators for Boolean Logic

Using & and | instead of && and || for boolean conditions disables short-circuit evaluation. This causes NullPointerException when the right side is null-sensitive: if (obj != null & obj.method() > 0) — obj.method() is ALWAYS called, even when obj is null. Always use && and || for boolean logic. Reserve & and | for intentional non-short-circuit scenarios (rare) or actual bitwise operations on integers.

Real-World Production Code Examples — Operators in Context

The following examples model idiomatic operator usage patterns found in real enterprise Java and Spring Boot codebases.

☕ JavaOrderService.java — Operators in Business Logic
package com.techsustainify.order.service;

import java.util.Objects;

public class OrderService {

    private static final int MAX_QUANTITY   = 100;
    private static final double TAX_RATE    = 0.18;
    private static final double DISCOUNT_THRESHOLD = 1000.0;

    // ✅ Relational + logical operators in validation
    public boolean isValidOrder(String productId, int quantity, double unitPrice) {
        return productId != null          // null check
            && !productId.isBlank()       // logical AND — short-circuit
            && quantity > 0               // relational
            && quantity <= MAX_QUANTITY   // relational
            && unitPrice > 0.0;           // relational
    }

    // ✅ Arithmetic + ternary operators in pricing calculation
    public double calculateTotal(int quantity, double unitPrice, String couponCode) {
        double subtotal = quantity * unitPrice;  // arithmetic

        // ✅ Ternary for inline conditional discount
        double discount = (subtotal > DISCOUNT_THRESHOLD) ? subtotal * 0.10 : 0.0;

        // ✅ Ternary for coupon code bonus
        double couponDiscount = (couponCode != null && couponCode.equals("SAVE20"))
                                ? subtotal * 0.20 : 0.0;

        double discountedAmount = subtotal - discount - couponDiscount;
        double tax              = discountedAmount * TAX_RATE;  // arithmetic
        return discountedAmount + tax;
    }

    // ✅ Bitwise operators for order status flags
    private static final int STATUS_PLACED    = 0b00001;  // 1
    private static final int STATUS_PAID      = 0b00010;  // 2
    private static final int STATUS_SHIPPED   = 0b00100;  // 4
    private static final int STATUS_DELIVERED = 0b01000;  // 8
    private static final int STATUS_CANCELLED = 0b10000;  // 16

    public int processOrder(int currentStatus) {
        // Set PAID flag using bitwise OR
        currentStatus |= STATUS_PAID;
        // Set SHIPPED flag
        currentStatus |= STATUS_SHIPPED;
        return currentStatus;
    }

    public boolean isDelivered(int status) {
        return (status & STATUS_DELIVERED) != 0;  // bitwise AND to check flag
    }

    // ✅ instanceof + pattern matching for polymorphic handling
    public double applyPaymentFee(Object payment) {
        if (payment instanceof CreditCardPayment cc) {
            return cc.getAmount() * 0.02;  // 2% fee
        } else if (payment instanceof UpiPayment upi) {
            return 0.0;   // No fee for UPI
        } else if (payment instanceof NetBankingPayment nb) {
            return nb.getAmount() >= 10000 ? 0.0 : 15.0;  // ternary
        }
        throw new IllegalArgumentException("Unknown payment type");
    }

    // ✅ Shift operators for fast power-of-2 page size calculation
    public int getPageSizeBytes(int pageSizeKB) {
        return pageSizeKB << 10;  // * 1024 — same as pageSizeKB * 2^10
    }
}
☕ JavaValidationUtils.java — Safe Operator Patterns
package com.techsustainify.util;

import java.util.Objects;

public class ValidationUtils {

    // ✅ Short-circuit AND for null-safe chained calls
    public static boolean isNonEmptyString(String s) {
        return s != null && !s.isEmpty() && !s.isBlank();
        // If s is null, the right sides are never evaluated — no NPE
    }

    // ✅ Objects.equals for null-safe object comparison (avoids manual null check)
    public static boolean safeEquals(Object a, Object b) {
        return Objects.equals(a, b);  // Handles null gracefully — no NPE
    }

    // ✅ Math.floorMod for always-positive modulus (unlike %)
    public static int circularIndex(int index, int size) {
        return Math.floorMod(index, size);  // Works correctly for negative index
    }

    // ✅ Math.addExact for overflow-safe addition
    public static long safeAdd(int a, int b) {
        try {
            return Math.addExact(a, b);
        } catch (ArithmeticException e) {
            throw new IllegalStateException("Integer overflow in addition", e);
        }
    }

    // ✅ Ternary for null-safe default values
    public static String defaultIfNull(String value, String defaultValue) {
        return value != null ? value : defaultValue;
        // Or simply: Objects.requireNonNullElse(value, defaultValue)
    }

    // ✅ Compound assignment in streaming aggregation
    public static double sumDiscounted(java.util.List<Double> prices, double discountPct) {
        double total = 0.0;
        for (double price : prices) {
            total += price * (1.0 - discountPct / 100.0);  // compound += each item
        }
        return total;
    }
}

Operators Flowchart — How Java Evaluates an Expression

This flowchart illustrates how the Java compiler and JVM evaluate an expression involving multiple operators — applying precedence, associativity, and short-circuit rules.

▶ Expression Encounterede.g., a + b * c > d && e != null
Parse
📐 Apply Operator PrecedenceHighest precedence operators first
Ordered
↔ Apply AssociativityLeft-to-right or right-to-left
Check for short-circuit
🔍 Short-Circuit Operator?&& or || present?
YES — && or ||
⚡ Evaluate Left SideResult determines if right runs
Left evaluated
🔍 Left side determines result?false && or true ||?
YES — result known
✅ Skip Right SideShort-circuit: right not evaluated
Done
🔄 Evaluate Right SideBoth sides needed
Done
✅ Final ResultExpression value computed

Code Execution Flow — from source to output

Java Operators Interview Questions — Beginner to Advanced

These questions are consistently asked in Java developer interviews at all levels. Mastering these will solidify your understanding of Java operators.

Practice Questions — Test Your Operators Knowledge

Challenge yourself with these practice questions. Attempt each independently before reading the answer — active recall is proven to be 2–3x more effective than passive reading.

1. What is the output? int a = 5, b = 2; System.out.println(a / b); System.out.println(a % b); System.out.println((double) a / b);

Easy

2. What is the output and why? String s1 = new String("hello"); String s2 = new String("hello"); String s3 = "hello"; String s4 = "hello"; System.out.println(s1 == s2); System.out.println(s3 == s4); System.out.println(s1.equals(s2));

Easy

3. What is the output? int x = 5; System.out.println(x++); System.out.println(x); System.out.println(++x); System.out.println(x);

Easy

4. What is the output? System.out.println(1 + 2 + "3"); System.out.println("1" + 2 + 3); System.out.println("1" + (2 + 3)); System.out.println(1 + 2 + 3 + "!");

Medium

5. What is the output? int count = 0; boolean a = (count++ > 0) || (++count > 0); System.out.println(count); int count2 = 0; boolean b = (count2++ > 0) && (++count2 > 0); System.out.println(count2);

Hard

6. Rewrite using the ternary operator: String result; if (marks >= 60) { result = "Pass"; } else { result = "Fail"; } And: is it always better to use ternary here?

Easy

7. What is the output? Explain the bitwise operations. int a = 0b1010; // 10 int b = 0b1100; // 12 System.out.println(a & b); System.out.println(a | b); System.out.println(a ^ b); System.out.println(~a);

Medium

8. Will this code compile? If so, what is the output? byte b = 10; b = b + 5; b += 5; System.out.println(b);

Hard

Conclusion — Operators: The Building Blocks of Every Java Expression

Operators are the foundation of every expression in Java. From the simplest int sum = a + b to complex business logic involving short-circuit null guards, bitwise permission flags, and ternary value selection — operators are present in every line of meaningful Java code. Understanding them deeply separates functional code from professional code.

The most important takeaways: always use .equals() for object comparison (never ==), leverage short-circuit evaluation (&& and ||) for null safety, use parentheses to make operator precedence explicit, avoid increment operators inside complex expressions, and never ignore integer overflow in production arithmetic. These are the habits that distinguish senior Java developers.

Operator CategoryOperatorsKey RuleCommon Pitfall
Arithmetic+ - * / %Integer division truncates7/2 = 3, not 3.5 — cast to double
Relational== != > < >= <=== on objects = reference checkUse .equals() for String/object content
Logical&& || !Short-circuit evaluation& and | don't short-circuit — risk NPE
Assignment= += -= etc.Compound operators have implicit castb = b + 5 fails for byte; b += 5 works
Unary++ -- + - !Prefix modifies first; postfix afterAvoid ++ inside complex expressions
Bitwise& | ^ ~Operates on bits — integers only~n = -(n+1) in two's complement
Shift<< >> >>>>> preserves sign; >>> fills with 0Use >>> for unsigned bit manipulation
Ternary?:Expression, not statementAvoid nested ternaries — use if-else
instanceofinstanceofAlways false for nullUse pattern matching (Java 16+) for clean cast

Your next step: Java Control Flow (if-else, switch) — where you'll apply relational and logical operators inside conditional statements and see how operator knowledge powers real branching logic in Java programs. ☕

Frequently Asked Questions — Java Operators