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
| Operator | Usage | Description |
|---|---|---|
+ | +a | Positive sign of the operand (rarely used) |
- | -a | Negates the sign of the operand |
++ | ++a / a++ | Increment operand by 1 (prefix / postfix) |
-- | --a / a-- | Decrement operand by 1 (prefix / postfix) |
! | !a | Inverts boolean value (true to false) |
~ | ~a | Inverts 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
}
}
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.
| Form | Syntax | Execution Order |
|---|---|---|
| Prefix | ++i, --i | Increment first-> then use the value in the expression |
| Postfix | i++, 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
}
}
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]
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
| Operator | Operand Type | Key Characteristics |
|---|---|---|
+, - | Numeric (byte/short promoted to int) | Sign display, - inverts value |
++, -- | Numeric | Prefix: increment then use; Postfix: use then increment |
! | boolean only | Inverts true/false |
~ | Integer | Inverts all bits, result = -(n+1) |
- 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
!flagpattern makes the code clear.