Beginner

Operators in Java

Learn about arithmetic, comparison, logical, bitwise, and assignment operators in Java with practical Docker-ready examples

Operators are the workhorses of every Java expression. They combine values, compare them, and update state — and because Java is a statically and strongly typed language, the type of each operand determines exactly how an operator behaves. The same + symbol adds two integers, adds two doubles, or concatenates strings, depending on what sits on either side of it.

Java inherits much of its operator syntax from C and C++, but with stricter rules: there is no implicit conversion between booleans and integers, integer overflow wraps silently, and division behaves very differently for integer and floating-point types. Understanding these details early will save hours of debugging later.

In this tutorial you’ll work with arithmetic, comparison, logical, bitwise, and assignment operators, see how operator precedence is resolved, and learn the quirks every Java developer eventually encounters.

Arithmetic Operators

Java provides the standard set of arithmetic operators: +, -, *, /, and % (modulo). The catch with / is that when both operands are integers, the result is also an integer — the fractional part is discarded.

Create a file named Arithmetic.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Arithmetic {
    public static void main(String[] args) {
        int a = 17;
        int b = 5;

        System.out.println("a + b = " + (a + b));
        System.out.println("a - b = " + (a - b));
        System.out.println("a * b = " + (a * b));
        System.out.println("a / b = " + (a / b));
        System.out.println("a % b = " + (a % b));

        // Floating-point division gives a fractional result
        double x = 17.0;
        double y = 5.0;
        System.out.println("x / y = " + (x / y));

        // Increment and decrement
        int counter = 10;
        System.out.println("counter++ = " + (counter++));
        System.out.println("after: counter = " + counter);
        System.out.println("++counter = " + (++counter));
    }
}

Notice how counter++ (postfix) returns the old value before incrementing, while ++counter (prefix) increments first and then returns the new value.

Comparison and Logical Operators

Comparison operators always produce a boolean (true or false). Logical operators combine booleans. Java’s && and || are short-circuiting — they stop evaluating as soon as the result is known.

Create a file named Logic.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Logic {
    public static void main(String[] args) {
        int age = 25;
        boolean hasLicense = true;

        System.out.println("age == 25: " + (age == 25));
        System.out.println("age != 30: " + (age != 30));
        System.out.println("age > 18:  " + (age > 18));
        System.out.println("age <= 21: " + (age <= 21));

        // Logical AND, OR, NOT
        boolean canDrive = age >= 18 && hasLicense;
        boolean isTeen = age >= 13 || age <= 19;
        System.out.println("canDrive: " + canDrive);
        System.out.println("isTeen:   " + isTeen);
        System.out.println("!canDrive: " + (!canDrive));

        // Short-circuit demonstration: the right side is never evaluated
        // because the left side is already false.
        int divisor = 0;
        boolean safe = divisor != 0 && (10 / divisor) > 0;
        System.out.println("safe: " + safe);
    }
}

Note that comparing object references with == checks identity, not equality of contents — for strings and other objects, use .equals(). We stick with primitive comparisons here to keep things focused.

Bitwise and Assignment Operators

Java offers the full set of C-style bitwise operators: &, |, ^, ~, <<, >>, and >>> (unsigned right shift, unique to Java). Compound assignment operators like +=, -=, *=, /=, and %= combine an operation with assignment.

Create a file named BitsAndAssign.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BitsAndAssign {
    public static void main(String[] args) {
        int flags = 0b1010;       // binary literal: decimal 10
        int mask  = 0b0110;       // decimal 6

        System.out.println("flags & mask = " + (flags & mask));  // AND
        System.out.println("flags | mask = " + (flags | mask));  // OR
        System.out.println("flags ^ mask = " + (flags ^ mask));  // XOR
        System.out.println("~flags       = " + (~flags));        // NOT
        System.out.println("flags << 2   = " + (flags << 2));    // left shift
        System.out.println("flags >> 1   = " + (flags >> 1));    // signed right shift

        // Unsigned right shift fills with zeros regardless of sign
        int negative = -8;
        System.out.println("-8 >>> 1     = " + (negative >>> 1));

        // Compound assignment
        int total = 100;
        total += 25;   // total = 125
        total -= 5;    // total = 120
        total *= 2;    // total = 240
        total /= 4;    // total = 60
        total %= 7;    // total = 4
        System.out.println("total = " + total);
    }
}

Operator Precedence and String Concatenation

Java evaluates operators in a strict precedence order: unary operators bind tightest, then multiplicative (*, /, %), then additive (+, -), then shifts, comparisons, equality, bitwise, logical, and finally assignment. When in doubt, parentheses make intent clear and cost nothing.

The + operator also performs string concatenation when at least one operand is a String. This interacts with left-to-right evaluation in ways that surprise newcomers.

Create a file named Precedence.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Precedence {
    public static void main(String[] args) {
        // Multiplication happens before addition
        int result = 2 + 3 * 4;
        System.out.println("2 + 3 * 4 = " + result);

        // Parentheses change the order
        int forced = (2 + 3) * 4;
        System.out.println("(2 + 3) * 4 = " + forced);

        // String concatenation pitfall: evaluated left-to-right
        System.out.println("Sum: " + 1 + 2);    // "Sum: 12"
        System.out.println("Sum: " + (1 + 2));  // "Sum: 3"

        // Ternary operator: condition ? whenTrue : whenFalse
        int score = 72;
        String grade = score >= 60 ? "Pass" : "Fail";
        System.out.println("Grade: " + grade);
    }
}

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Pull the official Eclipse Temurin JDK image
docker pull eclipse-temurin:21-jdk

# Compile and run each example
docker run --rm -v $(pwd):/app -w /app eclipse-temurin:21-jdk \
    sh -c "javac Arithmetic.java && java Arithmetic"

docker run --rm -v $(pwd):/app -w /app eclipse-temurin:21-jdk \
    sh -c "javac Logic.java && java Logic"

docker run --rm -v $(pwd):/app -w /app eclipse-temurin:21-jdk \
    sh -c "javac BitsAndAssign.java && java BitsAndAssign"

docker run --rm -v $(pwd):/app -w /app eclipse-temurin:21-jdk \
    sh -c "javac Precedence.java && java Precedence"

Expected Output

Running Arithmetic:

a + b = 22
a - b = 12
a * b = 85
a / b = 3
a % b = 2
x / y = 3.4
counter++ = 10
after: counter = 11
++counter = 12

Running Logic:

age == 25: true
age != 30: true
age > 18:  true
age <= 21: false
canDrive: true
isTeen:   true
!canDrive: false
safe: false

Running BitsAndAssign:

flags & mask = 2
flags | mask = 14
flags ^ mask = 12
~flags       = -11
flags << 2   = 40
flags >> 1   = 5
-8 >>> 1     = 2147483644
total = 4

Running Precedence:

2 + 3 * 4 = 14
(2 + 3) * 4 = 20
Sum: 12
Sum: 3
Grade: Pass

Key Concepts

  • Integer vs floating-point division17 / 5 yields 3, while 17.0 / 5.0 yields 3.4. Mixing types promotes the result to the wider type.
  • Short-circuit evaluation&& and || skip the right operand once the answer is determined, which is useful for guarding against null or division by zero.
  • == on objects checks identity — Use .equals() to compare object contents like String values. This tutorial used only primitives where == is safe.
  • Unsigned right shift >>> — Java is one of the few languages with a dedicated unsigned shift; >> preserves the sign bit, >>> does not.
  • String concatenation is left-to-right"x: " + 1 + 2 becomes "x: 12", not "x: 3". Wrap arithmetic in parentheses when concatenating.
  • Compound assignment includes an implicit castbyte b = 10; b += 200; compiles, while b = b + 200; does not. The compound form silently narrows the result.
  • Use parentheses for clarity — Java’s precedence rules are well-defined, but explicit grouping makes code easier to read and review.

Running Today

All examples can be run using Docker:

docker pull eclipse-temurin:21-jdk
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining