Java Statements
A statement is a single complete instruction that the JVM executes. A Java method body is a sequence of statements, run from top to bottom unless a control-flow statement redirects execution. Understanding the categories of statements clarifies what the compiler expects at each position in a program.
Expression Statements
An expression produces a value. An expression statement is an expression followed by a semicolon, executed for its side effect.
count = count + 1; // assignment
count++; // increment
System.out.println(x); // method call
new Thread(task).start(); // object creation followed by a call
Only certain expressions may stand alone as statements: assignments, increments and decrements, method calls, and object creation. The compiler rejects an expression whose value would simply be discarded:
count + 1; // compile error: not a statement
x == 5; // compile error: not a statement
"hello"; // compile error: not a statement
This rule catches a common mistake. Writing x == 5; when x = 5; was intended is a compile error in Java rather than a silent no-op as in C.
Declaration Statements
A declaration statement introduces a variable, optionally with an initial value.
int total;
int total = 0;
String name = "Ada";
var list = new ArrayList<String>();
final double TAX_RATE = 0.18;
final makes the variable assignable exactly once. After TAX_RATE has a value, TAX_RATE = 0.2; is a compile error. The compiler verifies that a local variable has definitely been assigned before every read:
int size;
if (args.length > 0) {
size = 10;
}
System.out.println(size); // compile error: size might not have been initialized
The if branch assigns size, but the path where the condition is false does not, so the compiler refuses. Adding an else that assigns size, or initializing it at declaration, fixes the error.
Control-Flow Statements
Control-flow statements change the order in which other statements run.
Selection
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else {
grade = 'C';
}
switch (day) {
case "SAT", "SUN" -> System.out.println("Weekend");
default -> System.out.println("Weekday");
}
Iteration
for (int i = 0; i < 5; i++) { ... }
for (String item : items) { ... }
while (queue.hasNext()) { ... }
do { ... } while (retry);
Jump
break; // exit the nearest loop or switch
continue; // skip to the next loop iteration
return value; // exit the method
throw new IllegalStateException("bad state"); // raise an exception
Each of these has its own lesson. What matters here is that they are statements like any other, and can be placed wherever a statement is allowed.
Block Statements
A block is zero or more statements enclosed in braces. The block itself counts as a single statement.
{
int temp = a;
a = b;
b = temp;
}
Because a block is one statement, it can appear anywhere one statement is expected, which is why if (cond) { ... } works: the if requires exactly one statement as its body, and the block satisfies that requirement no matter how many statements it holds.
A variable declared inside a block exists only within that block. After the closing brace, temp above no longer exists, and declaring another temp afterwards is fine.
A bare block (not attached to if, for, or a method) is rarely used, but it is legal and occasionally useful to limit a variable's scope within a long method.
Empty Statements
A lone semicolon is an empty statement. It does nothing.
;
Most of the time an empty statement is a mistake:
for (int i = 0; i < 10; i++); // <-- loop body is the empty statement
{
System.out.println(i); // runs once, and i is out of scope: compile error
}
if (ready); // <-- the if controls nothing
start(); // always runs
The trailing semicolon after ) silently ends the loop or conditional. The following block or line is then an independent statement. Compilers and IDEs usually warn about this, and the fix is simply to remove the semicolon.
Labeled Statements
A statement can be given a label so that break and continue can refer to it. This is used almost exclusively with nested loops.
outer:
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == target) {
System.out.println("Found at " + row + "," + col);
break outer; // exits BOTH loops
}
}
}
Without the label, break would exit only the inner loop and the outer loop would continue scanning. The label is an identifier followed by a colon, placed before the statement it names.
Statement Order and Sequential Execution
Within a block, statements execute strictly in order. Each statement completes before the next begins. This includes method calls: a call does not return until the called method has finished every one of its own statements.
int a = 5; // 1
int b = a * 2; // 2: a is 5, so b is 10
a = 20; // 3
System.out.println(b); // 4: prints 10, not 40
Step 2 computed b from the value a had at that moment. Changing a afterwards does not retroactively change b. Variables hold values, not formulas. This is obvious to experienced programmers but is a frequent source of confusion for beginners coming from spreadsheets.
Statements Versus Expressions
The distinction becomes important in features that require one or the other.
| Expression | Statement | |
|---|---|---|
| Produces a value | Yes | No |
| Can appear inside another expression | Yes | No |
| Examples | a + b, x > 0, list.size(), new Point(1, 2) | int x = 1;, if (...) {...}, return; |
Some constructs exist in both forms. A traditional switch is a statement; a switch expression (Java 14+) produces a value:
// statement form
String label;
switch (code) {
case 1 -> label = "one";
case 2 -> label = "two";
default -> label = "other";
}
// expression form
String label = switch (code) {
case 1 -> "one";
case 2 -> "two";
default -> "other";
};
The expression form ends with a semicolon because the whole String label = switch ... ; is a declaration statement. The switch itself is the expression on the right-hand side.
Lambda bodies follow the same rule. x -> x * 2 has an expression body; x -> { return x * 2; } has a statement body (a block). Both are valid, and the block form is needed when the body requires more than one statement.
Where Statements May Appear
Statements may appear only inside method bodies, constructor bodies, initializer blocks, and lambda bodies. They may not appear directly inside a class body:
public class Config {
int port = 8080; // field declaration: allowed
System.out.println(port); // compile error: statement outside a method
}
A class body holds declarations (fields, methods, constructors, nested types), not executable statements. Code that must run when the class is loaded or when an object is created goes into a static initializer, a constructor, or an instance initializer block:
public class Config {
static final Map<String, String> DEFAULTS = new HashMap<>();
static { // static initializer: runs once when the class loads
DEFAULTS.put("port", "8080");
DEFAULTS.put("host", "localhost");
}
}