Skip to main content

Ch 3.2 Unary Operators

Unary operators are operators that take only a single operand. They include sign operators (+, -), increment/decrement operators (++, --), logical NOT operator (!), and bitwise NOT operator (~).


1. Summary of Unary Operators

OperatorUsageDescription
++aPositive sign of the operand (rarely used)
--aNegates the sign of the operand
++++a / a++Increment operand by 1 (prefix / postfix)
----a / a--Decrement operand by 1 (prefix / postfix)
!!aInverts boolean value (true to false)
~~aInverts all bits of an integer

2. Sign Operators (+, -)

These are the same concept as positive/negative signs in mathematics.

  • +a: Returns the value of the operand as-is (effectively does nothing).
  • -a: Returns the value with the sign inverted.
public class SignOperator {
public static void main(String[] args) {
int a = 10;
int b = -a; // b = -10, a is unchanged
int c = -b; // c = 10

System.out.println("a = " + a); // 10
System.out.println("b = " + b); // -10
System.out.println("c = " + c); // 10

// Negating a negative gives a positive
int temperature = -15;
System.out.println("Temperature: " + temperature); // -15
System.out.println("Absolute-like: " + (-temperature)); // 15
}
}
int Promotion (byte, short, char)

When the sign operator is applied to byte, short, or char types, the result is automatically promoted to int type.

byte b = 10;
// byte result = -b; // Compile error! -b result is int type
int result = -b; // OK: store in int
System.out.println(result); // -10

// To store in byte with explicit cast:
byte b2 = (byte)(-b); // Explicit cast required

It can only be used on primitive types other than boolean (and char for the + sign operator).


3. Increment/Decrement Operators (++, --)

These operators increase or decrease the value of the operand by 1. They are most frequently used in loops.

  • Increment operator (++): Increases the operand's value by 1
  • Decrement operator (--): Decreases the operand's value by 1

Prefix vs Postfix Comparison

The position of the operator determines when the expression is evaluated.

FormSyntaxExecution Order
Prefix++i, --iIncrement first-> then use the value in the expression
Postfixi++, i--Use current value first-> then increment
public class IncrementDecrement {
public static void main(String[] args) {
// Postfix: use current value first, then increment
int i = 5;
int j = i++; // Assign current value of i (5) to j, then increment i to 6
System.out.println("Postfix - i: " + i + ", j: " + j); // i=6, j=5

// Prefix: increment first, then use incremented value
int x = 5;
int y = ++x; // Increment x to 6 first, then assign 6 to y
System.out.println("Prefix - x: " + x + ", y: " + y); // x=6, y=6

// Decrement operator
int a = 10;
int b = a--; // b=10, a=9
int c = --a; // a=8, c=8
System.out.println("Decrement - a: " + a + ", b: " + b + ", c: " + c); // a=8, b=10, c=8
}
}

No Difference When Used Standalone

When increment/decrement operators are used standalone(without other operations or assignments), there is no difference between prefix and postfix.

int n = 0;
n++; // n = 1 (postfix)
++n; // n = 2 (prefix) -> same result when used standalone
n--; // n = 1 (postfix)
--n; // n = 0 (prefix) -> same result when used standalone

Prefix/Postfix in Expressions (Advanced)

public class PrefixPostfixInExpr {
public static void main(String[] args) {
int a = 3;
// Mixed use in an expression -> complex, avoid in practice
int result = a++ + ++a; // 3 + 5 = 8 (a becomes 5)
// Explanation: a++(use current value 3, then a=4), ++a(increment a to 5, then use 5)
System.out.println("result = " + result); // 8
System.out.println("a = " + a); // 5
}
}
Do not use increment operators in complex expressions

Using increment operators multiple times in a single expression like a++ + ++a drastically reduces readability and is prone to errors. It is recommended to use them standalone as loop counters.

Increment Operators in Loops

public class LoopIncrement {
public static void main(String[] args) {
// i++ (postfix) in for loop - most common pattern
for (int i = 0; i < 5; i++) {
System.out.print(i + " "); // 0 1 2 3 4
}
System.out.println();

// ++i (prefix) in for loop - same result when used standalone
for (int i = 0; i < 5; ++i) {
System.out.print(i + " "); // 0 1 2 3 4
}
System.out.println();

// Decrement operator in while loop
int count = 5;
while (count > 0) {
System.out.print(count + " "); // 5 4 3 2 1
count--;
}
System.out.println();
}
}
++i vs i++ Performance (Theory)

For Java primitives like int, the JIT compiler optimizes them so there is no practical performance difference. In C++, however, prefix is more efficient for iterator objects. In Java, this is just a style difference; conventionally, i++ is used more often.


4. Logical NOT Operator (!)

Inverts a boolean value. true becomes false and false becomes true.

public class LogicalNot {
public static void main(String[] args) {
boolean isLoggedIn = false;
boolean isGuest = !isLoggedIn; // true

System.out.println("Login status: " + isLoggedIn); // false
System.out.println("Is guest: " + isGuest); // true

// Usage in conditionals
int age = 17;
boolean isAdult = (age >= 18);
if (!isAdult) {
System.out.println("This person is a minor.");
}

// Double negation: !!x equals x (meaningless)
boolean flag = true;
System.out.println(!flag); // false
System.out.println(!!flag); // true (not recommended)
}
}

The ! operator can only be used on boolean types. Using it on other types causes a compile error.

int n = 5;
// boolean b = !n; // Compile error! Cannot use ! on int

5. Bitwise NOT Operator (~)

Inverts all bits of an integer operand (0 becomes 1, 1 becomes 0). The result is equivalent to -(n + 1). This is due to the two's complement representation.

public class BitwiseNot {
public static void main(String[] args) {
int a = 5; // Binary: 00000000 00000000 00000000 00000101
int b = ~a; // Binary: 11111111 11111111 11111111 11111010 = -6
System.out.println("~5 = " + b); // -6

int c = 0;
System.out.println("~0 = " + (~c)); // -1

int d = -1; // All bits are 1
System.out.println("~(-1) = " + (~d)); // 0

// Formula: ~n == -(n + 1)
for (int n = -3; n <= 3; n++) {
System.out.println("~" + n + " = " + (~n) + " [verify: -("+n+"+1) = " + (-(n+1)) + "]");
}
}
}

Output:

~5 = -6
~0 = -1
~(-1) = 0
~-3 = 2 [verify: -(-3+1) = 2]
~-2 = 1 [verify: -(-2+1) = 1]
~-1 = 0 [verify: -(-1+1) = 0]
~0 = -1 [verify: -(0+1) = -1]
~1 = -2 [verify: -(1+1) = -2]
~2 = -3 [verify: -(2+1) = -3]
~3 = -4 [verify: -(3+1) = -4]
Uses of Bitwise NOT

The ~ operator is used in bit masking and turning off specific bits.

int flags = 0b1111;    // All bits ON
int mask = 0b0010; // Want to turn off the 2nd bit
flags = flags & (~mask); // flags & 0b1101 = 0b1101
System.out.println(Integer.toBinaryString(flags)); // 1101

6. Notes on Using Unary Operators

Type Promotion After Operation

When unary arithmetic operators are applied to byte or short types, the result is promoted to int.

byte b1 = 100;
byte b2 = 20;

// byte result = b1 + b2; // Compile error: result is int
int result = b1 + b2; // OK: 120

// Compound assignment operator handles casting internally
b1 += b2; // b1 = (byte)(b1 + b2) = 120
System.out.println(b1); // 120

Watch Out for Overflow

If the increment/decrement operator causes a value to exceed the data type's maximum, overflow occurs.

int max = Integer.MAX_VALUE; // 2147483647
max++;
System.out.println(max); // -2147483648 (overflow!)

int min = Integer.MIN_VALUE; // -2147483648
min--;
System.out.println(min); // 2147483647 (underflow!)

7. Practical Example: Toggle Feature Implementation Pattern

Toggle is a switch-like feature that turns a state on and off. It can be implemented simply using the ! operator.

public class ToggleExample {
public static void main(String[] args) {
// Pattern 1: Boolean toggle
boolean isPlaying = false;
System.out.println("Initial state: " + (isPlaying ? "Playing" : "Stopped"));

// Invert state on each button press
isPlaying = !isPlaying;
System.out.println("Click 1: " + (isPlaying ? "Playing" : "Stopped")); // Playing

isPlaying = !isPlaying;
System.out.println("Click 2: " + (isPlaying ? "Playing" : "Stopped")); // Stopped

isPlaying = !isPlaying;
System.out.println("Click 3: " + (isPlaying ? "Playing" : "Stopped")); // Playing

System.out.println();

// Pattern 2: Counter using increment operator
int clickCount = 0;
System.out.println("Click count: " + clickCount); // 0

clickCount++;
clickCount++;
clickCount++;
System.out.println("After 3 clicks: " + clickCount); // 3

clickCount--;
System.out.println("After undo: " + clickCount); // 2

System.out.println();

// Pattern 3: Direction toggle using sign operator
int direction = 1; // 1: right, -1: left
System.out.println("Initial direction: " + (direction > 0 ? "Right" : "Left"));

direction = -direction; // Invert direction
System.out.println("After inversion: " + (direction > 0 ? "Right" : "Left")); // Left

direction = -direction;
System.out.println("After re-inversion: " + (direction > 0 ? "Right" : "Left")); // Right

System.out.println();

// Pattern 4: Toggle using bitwise XOR
int lamp = 0; // 0: OFF, 1: ON
System.out.println("Lamp: " + (lamp == 1 ? "ON" : "OFF")); // OFF
lamp ^= 1;
System.out.println("After switch: " + (lamp == 1 ? "ON" : "OFF")); // ON
lamp ^= 1;
System.out.println("After switch: " + (lamp == 1 ? "ON" : "OFF")); // OFF
}
}

Output:

Initial state: Stopped
Click 1: Playing
Click 2: Stopped
Click 3: Playing

Click count: 0
After 3 clicks: 3
After undo: 2

Initial direction: Right
After inversion: Left
After re-inversion: Right

Lamp: OFF
After switch: ON
After switch: OFF

8. Key Summary

OperatorOperand TypeKey Characteristics
+, -Numeric (byte/short promoted to int)Sign display, - inverts value
++, --NumericPrefix: increment then use; Postfix: use then increment
!boolean onlyInverts true/false
~IntegerInverts all bits, result = -(n+1)
Best Practices
  • For simple counters, consistently choose either i++ or ++i (no performance difference in Java).
  • Avoid combining increment operators with other operators in the same expression.
  • For toggle logic, using the !flag pattern makes the code clear.