☕ Java

Unary Operators

Unary operators take a single operand. Java has five: unary plus, unary minus, increment, decrement, and logical NOT. The increment and decrement operators have prefix and postfix forms that behave differently — a distinction that trips up developers at every level.

The Five Unary Operators

Java has five unary operators — each takes exactly one operand:
Java
+    // unary plus  — explicitly marks a value as positive (rarely used)
-    // unary minus — negates a value
++   // increment   — adds 1 (prefix and postfix forms)
--   // decrement   — subtracts 1 (prefix and postfix forms)
!    // logical NOT — inverts a boolean

+ and - Unary Operators

Unary minus negates a numeric value. Unary plus is syntactically valid but rarely used — it doesn't change the value, but it does trigger type promotion to int for byte and short.
Java
// Unary minus — negates:
int a = 5;
int b = -a;      // -5
System.out.println(-10);    // -10
System.out.println(-(-5));  //  5double negation

// Negating variables:
int temperature = 30;
int belowZero = -temperature;   // -30

double d = 3.14;
double neg = -d;   // -3.14

// Unary minus on expressions:
int x = 3, y = 4;
int result = -(x + y);   // -(7) = -7

// Unary plus — promotes byte/short to int, otherwise no effect:
byte b = 42;
// byte promoted = +b;   // COMPILE ERROR — +b is int, not byte
int promoted = +b;        // 42 — type promoted to int

int i = 5;
int same = +i;   // 5 — no change for int

// Practical use of unary minus:
int[] temps = {-10, 5, -3, 8, -15};
for (int t : temps) {
    if (t < 0) System.out.println("Below zero: " + (-t) + " degrees cold");
}

++ and -- Prefix vs Postfix

Increment and decrement operators exist in two forms. The position of the operator — before or after the operand — determines when the update happens relative to the value being used.
Java
// Prefix (++x) — increment FIRST, then use the new value:
int a = 5;
int b = ++a;
System.out.println(a);  // 6 — incremented
System.out.println(b);  // 6 — received the incremented value

// Postfix (x++) — use the current value FIRST, then increment:
int x = 5;
int y = x++;
System.out.println(x);  // 6 — incremented
System.out.println(y);  // 5 — received the ORIGINAL value

// Same with decrement:
int m = 10;
int n = --m;   // prefix: m=9, n=9
System.out.println(m + " " + n);  // 9 9

int p = 10;
int q = p--;   // postfix: q=10, then p=9
System.out.println(p + " " + q);  // 9 10

// In isolation — no difference:
int count = 0;
count++;   // same result as ++count when not in an expression
++count;   // both just add 1

// In expressions — significant difference:
int i = 3;
System.out.println(i++ * 2);   // 6 — uses 3, then i becomes 4
System.out.println(++i * 2);   // 10 — i becomes 5 first, then 5*2

// Classic postfix trap:
int val = 5;
val = val++;   // val is STILL 5!
// Sequence: temp=val(5), val=val+1(6), val=temp(5) — postfix returns original
System.out.println(val);  // 5 — not 6!

// The correct way to increment and keep:
val = val + 1;   // or: val++; (as standalone statement, not expression)

++ and -- in Loops

Increment and decrement are most commonly seen in for loops. In the loop update clause, prefix and postfix produce identical results — there's no expression context, so the timing difference doesn't matter.
Java
// In for loop update — i++ and ++i are identical in effect:
for (int i = 0; i < 5; i++) {
    System.out.print(i + " ");   // 0 1 2 3 4
}

for (int i = 0; i < 5; ++i) {
    System.out.print(i + " ");   // 0 1 2 3 4 — identical output
}

// Counting down with --:
for (int i = 5; i > 0; i--) {
    System.out.print(i + " ");   // 5 4 3 2 1
}

// While loop:
int n = 10;
while (n-- > 0) {
    System.out.print(n + " ");   // 9 8 7 6 5 4 3 2 1 0
}
// Note: n-- uses n (10) for the > 0 check, then decrements
// Loop runs while n was > 0, but prints already-decremented n

// Contrast with prefix:
n = 10;
while (--n > 0) {
    System.out.print(n + " ");   // 9 8 7 6 5 4 3 2 1
}
// --n decrements first (109), then checks 9 > 0
// Stops when --n produces 0 (which is not > 0)

! — Logical NOT

! inverts a boolean value. It's unary, prefix-only, and has high precedence — be careful with complex expressions.
Java
// Basic NOT:
System.out.println(!true);    // false
System.out.println(!false);   // true

// NOT with boolean variables:
boolean isLoggedIn = false;
if (!isLoggedIn) {
    System.out.println("Please log in");
}

// NOT with comparisons — parentheses control precedence:
int x = 5;
System.out.println(!(x > 3));    // false — NOT(true) = false
System.out.println(!x > 3);      // COMPILE ERROR — !x is invalid (!int)

// De Morgan's law — simplify negated conditions:
// !(A && B)  ==  (!A || !B)
// !(A || B)  ==  (!A && !B)

// Apply De Morgan to simplify:
if (!(age < 18 || score < 50)) { }          // hard to read
if (age >= 18 && score >= 50) { }           // cleaner equivalent

if (!(isAdmin && isVerified)) { }           // readable but complex
if (!isAdmin || !isVerified) { }            // De Morgan applied

// NOT with method return values:
List<String> list = List.of("a", "b", "c");
if (!list.isEmpty()) {
    System.out.println("List has " + list.size() + " items");
}

if (!str.contains("@")) {
    throw new IllegalArgumentException("Not a valid email");
}

~ — Bitwise NOT (Complement)

~ is the bitwise complement operator — it inverts every bit of an integer. It's sometimes categorized with unary operators because it takes one operand.
Java
// ~ inverts all bits — result is -(n+1):
System.out.println(~0);     // -1
System.out.println(~1);     // -2
System.out.println(~5);     // -6
System.out.println(~(-1));  //  0

// Formula: ~n == -(n + 1)

// Practical uses:
// 1. Check indexOf results — indexOf returns -1 if not found:
String text = "Hello World";
if (~text.indexOf("World") != 0) {    // ~(-1) == 0, so != 0 means found
    System.out.println("Found");
}
// More readable alternative:
if (text.indexOf("World") != -1) {
    System.out.println("Found");
}
// Or best:
if (text.contains("World")) {
    System.out.println("Found");
}

// 2. Creating inverse bitmasks:
int mask = 0x0F;          // 0000 1111
int inverse = ~mask;       // 1111 0000

// 3. Clearing bits with ~:
int flags = 0xFF;
int WRITE_FLAG = 0b00000010;
flags &= ~WRITE_FLAG;      // clear the write bit