Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The -- operator is a unary decrement operator in Java that reduces the value of a numeric operand by exactly one. For primitive numeric types (including char), it modifies the value directly. When applied to wrapper classes (such as Integer or Double), the operator unboxes the primitive value, decrements it, auto-boxes the result into a new object, and updates the variable to reference this new object, as Java wrapper classes are strictly immutable. The operator functions in two distinct modes based on its placement relative to the operand, dictating the order of evaluation between the decrement operation and the resolution of the expression’s value.

Prefix Decrement (--operand)

In prefix form, the operator precedes the operand. The Java Virtual Machine (JVM) decrements the variable’s value first, and the expression evaluates to this newly decremented value.
int a = 10;
int b = --a; 
// Step 1: 'a' is decremented to 9.
// Step 2: The expression evaluates to 9, assigning 9 to 'b'.
// Result: a = 9, b = 9.

Postfix Decrement (operand--)

In postfix form, the operator follows the operand. The expression captures and evaluates to the variable’s original value. The JVM decrements the variable immediately after this original value is captured, strictly before any subsequent parts of a larger expression are evaluated.
int x = 10;
int y = (x--) + x; 
// Step 1: 'x--' evaluates to the original value (10).
// Step 2: 'x' is immediately decremented to 9.
// Step 3: The second 'x' evaluates to the new value (9).
// Result: y = 19, x = 9.

Technical Characteristics

Implicit Narrowing Conversion When applied to narrower primitive types (such as byte, short, or char), the -- operator adheres to standard binary numeric promotion rules prior to subtraction. The variable’s value and the literal 1 are first promoted to int. After the subtraction is performed, the JVM applies an implicit narrowing primitive conversion to the result, casting it back to the original narrower type before assignment.
byte b = 5;
b--; // Compiles successfully. Equivalent to: b = (byte)(b - 1);
b = b - 1; // Compilation error: incompatible types (int cannot be converted to byte).
L-Value Requirement The operand must be a mutable variable (an l-value). The operator cannot be applied to literals, constants (final variables), or the evaluated results of complex expressions.
int val = 5--; // Compilation error: unexpected type (requires variable, found value).
Bytecode Execution and Non-Atomicity The bytecode generated by the -- operator depends on the operand’s scope and type. For local int variables, the Java compiler generates a single iinc (integer increment/decrement) instruction. This instruction modifies the local variable directly without loading it onto the operand stack. Conversely, for fields, array elements, non-int primitives (such as long, float, or double), and narrower local integral types (byte, short, and char), the operator compiles to a multi-step read-modify-write sequence utilizing the operand stack. For narrower types, this sequence explicitly includes a truncation instruction (e.g., i2b for byte) to enforce the required narrowing conversion:
  1. Load the current value from memory onto the operand stack (e.g., iload).
  2. Push the constant 1 onto the stack (e.g., iconst_1).
  3. Perform the subtraction operation (e.g., isub).
  4. Apply narrowing conversion if applicable (e.g., i2b).
  5. Store the new value from the stack back into memory (e.g., istore).
Regardless of whether it compiles to a single iinc instruction or a multi-step stack sequence, the -- operator is not atomic at the hardware level and is not thread-safe. In concurrent environments, applying -- to a shared variable without synchronization will result in race conditions and lost updates.
Master Java with Deep Grasping Methodology!Learn More