Topic 32 of 119 4. Control Flow in Java Interactive Tutorial

The Java if Statement: Conditional Execution Explained

9 mins read Last updated: 22 Aug 2026 20,536 views

Direct Answer & Core Concept

The `if` statement is Java's simplest decision construct: it evaluates one boolean condition, and runs the statement or block that follows only if that condition is true. Nothing is required after it, so an `if` on its own is a complete, valid statement. Three properties matter in practice. First, the condition must be strictly `boolean`, so `if (count)` and `if (name)` are compile errors where C would accept them. Second, the condition is evaluated exactly once, so it is safe to put a method call with side effects inside it, and combined conditions using `&&` and `||` short-circuit rather than always evaluating both sides. Third, the braces define the extent of the branch: without them only the single next statement belongs to the `if`, which is legal but the source of the most common conditional bug. If you want the decision to produce a value rather than perform an action, an `if` cannot do that, because it is a statement and not an expression; use a ternary or a `switch` expression instead. When the surrounding code has nothing left to do after the branch, prefer returning early from the method over adding an `else` block.

Detailed Explanation & Mechanics

1. The Basic Form

The if statement evaluates a condition and, only if it is true, executes the statement that follows. There is nothing else required, which is what distinguishes it from if-else.

Main.java
Run Online
int age = 20;
if (age >= 18) {
    System.out.println("Eligible to vote!");
    System.out.println("Welcome to active citizenship.");
}

With age at 20 both lines print. When the condition is false, the block is skipped entirely and execution simply continues after it.

Main.java
Run Online
int score = 45;
if (score >= 50) {
    System.out.println("This line never prints.");
}

Nothing is printed here, and that is the whole behaviour. There is no implicit "otherwise" and no error, so an if that never fires is entirely legal.

PartPurpose
ifThe keyword that starts the conditional
()Hold the condition, parentheses are mandatory
The conditionMust be a boolean expression
The bodyOne statement, or a block of statements in braces
elseOptional, and not part of this statement

The parentheses are not optional, which is a small syntactic difference from C-like languages that let you write if x > 0.

Main.java
Run Online
if (age >= 18) {
} // correct
if age >= 18 {
} // syntax error

2. The Condition Must Be Boolean

Java has no concept of truthy and falsy values. The condition has to be a boolean expression, and anything else is a compile error.

Main.java
Run Online
if (1) {
} // error: incompatible types: int cannot be converted to boolean
if (someName) {
} // error: incompatible types: String cannot be converted to boolean
if (values) {
} // error: incompatible types: int[] cannot be converted to boolean

This is stricter than C and C++, where any nonzero value counts as true and a null pointer counts as false. Porting that habit produces a compile error rather than a silent misbehaviour, which is the kind way to discover the difference.

Main.java
Run Online
int count = items.size();
if (count > 0) {
} // correct, and it also says what you mean

Prefer the explicit comparison even where a bare test would compile in another language, because if (count > 0) tells the reader the intent rather than making them infer it.

The Boolean **wrapper** is the one type that is accepted but can still fail at run time.

Main.java
Run Online
Boolean flag = null;
if (flag) {
} // throws NullPointerException on unboxing

Because a Boolean has to be unboxed to be tested, and unboxing null throws. The fix is either a primitive boolean, or an explicit null check, and the && ordering is what makes it safe.

Main.java
Run Online
if (flag != null && flag) {
} // safe, the right side runs only if flag is not null

3. The Condition Is Evaluated Once

The condition is computed exactly one time, however many times the branch body runs. This matters when the condition has a side effect.

Main.java
Run Online
static int calls = 0;
static boolean check() {
    calls++;
    return true;
}if (check()) {
} // one call

Verified behaviour, check() is invoked once and calls ends at 1. A method call in the condition is therefore safe, but it also means you should not rely on it being called repeatedly inside a loop condition, because each iteration does call it again.

Main.java
Run Online
static int calls = 0;
if (check() && check()) {
} // two calls, left operand is true

With check() returning true the left operand does not decide the outcome, so the right one is evaluated and calls reaches 2.

4. Combining Conditions with Short-Circuit

Because && and || short-circuit, the right-hand operand is only evaluated when it can still affect the result.

Main.java
Run Online
if (false && rhs()) {
} // rhs() is NEVER called
if (true || rhs()) {
} // rhs() is NEVER called
if (true && rhs()) {
} // rhs() IS called
if (false || rhs()) {
} // rhs() IS called

Verified: in both of the first two cases the side effect inside rhs() never fires. This is the mechanism behind every null-safe comparison in Java, and it is a correctness tool rather than only a performance one.

Main.java
Run Online
String name = null;
if (name != null && name.isEmpty()) {
} // safe, no NPE

Reordering those two operands breaks it, because name.isEmpty() is then reached with name null.

Main.java
Run Online
if (name.isEmpty() && name != null) {
} // throws NullPointerException

5. Braces Define the Branch

The braces decide how many statements belong to the if. Without them only the immediately following statement does, and everything after runs unconditionally.

Main.java
Run Online
int age = 20;
if (age >= 18) System.out.println("can vote");
System.out.println("ALWAYS runs");

Both lines print here. The second is not inside the if at all, which is legal but easy to misread. With braces the grouping is explicit.

Main.java
Run Online
if (age >= 18) {
    System.out.println("can vote");
}System.out.println("ALWAYS runs");

Now only the first line is conditional. The practical rule is to always use braces, even for a single statement, and most Java style guides require it.

6. The Real Hazard Is the Later Edit

The braceless form rarely causes a problem when it is written, because the author can see it. The danger is a later edit that adds a second line to a branch that had only one.

Main.java
Run Online
// written this way, with no bug
if (databaseIsUp) connect();
logRequest();
// someone later adds a line, forgetting the braces
if (databaseIsUp) connect();
logRequest();
// now runs unconditionally, and is easy to misread as conditional

Verified output is connect only when databaseIsUp is true, but the moment a second statement is added underneath it silently executes every time. This is the same class of bug as the famous Apple TLS "goto fail" error, where a missing brace caused a security check to be skipped, and it is why braces are not merely a style preference.

Main.java
Run Online
// with braces, adding a line cannot change the meaning
if (databaseIsUp) {
    connect();
}logRequest();

7. The Dangling Else

An else always attaches to the nearest unmatched if, so leaving braces off can change which branch it belongs to.

Main.java
Run Online
if (a == 0) if (a == 1) System.out.println("A");
else System.out.println("B");

The else binds to the inner if, not the outer one, because the inner one is the closest without an else. With a equal to 0 the output is B, since the inner condition fails and its else runs. This is where the braceless form stops being a readability nit and starts changing behaviour, so always use braces whenever an if and an else appear together.

8. Variables Are Scoped to the Block

A variable declared inside the braces belongs to that block and cannot be used outside it.

Main.java
Run Online
if (true) {
    int message = "hello";
    System.out.println(message);
    // fine
}System.out.println(message);
// error: cannot find symbol

Note the useful consequence for a variable declared outside: you can reassign it inside the if and the new value is visible afterwards.

Main.java
Run Online
int n = 1;
if (true) {
    n = 2;
}System.out.println(n);
// 2

Redeclaring the same name inside the block is a different story, and the rule is stricter than in many languages.

Main.java
Run Online
int n = 1;
if (true) {
    int n = 2;
} // error: variable n is already defined in method main

Shadowing a local is rejected outright. Shadowing a **field** is allowed, since fields and locals live in different namespaces, but it is worth avoiding because the inner declaration silently hides the field.

Main.java
Run Online
static int n = 100;
// a field
if (true) {
    int n = 2;
} // legal, and now hides the field

9. Definite Assignment Applies

If a variable is declared without an initialiser, the compiler requires proof it was assigned before you read it, even inside an if.

Main.java
Run Online
int y;
boolean condition = true;
if (condition) y = 1;
System.out.println(y);
// error: variable y might not have been initialized

The compiler cannot see that condition happens to be true, because the value is only known at run time. Giving it a default, or covering every path with an else, satisfies the rule.

Main.java
Run Online
int y = 0;
if (condition) y = 1;
System.out.println(y);
// fine

10. An if Cannot Produce a Value

An if is a **statement**, so it performs an action and yields nothing. You cannot assign its outcome or pass it to a method.

Main.java
Run Online
int result = if (condition) 1;
// error: illegal start of expression
System.out.println(if (condition) 1);
// error: illegal start of expression

When you need a value from a condition, the ternary operator is an **expression** and works exactly where if cannot.

Main.java
Run Online
int result = condition ? 1 : 0;
// fine

This is the single most important structural difference between the two, and it is the reason an if followed by an assignment is so common when a ternary would do.

11. When to Prefer an Early Return

An if that guards the only interesting work in a method reads better as an early return than as a branch wrapped around everything else.

Main.java
Run Online
// wrapped, the real work sits one level in
String describe(int value) {
    if (value < 0) {
        return "negative";
    } else {
        return "non-negative";
    }
}// early return, the main path is unindented
String describe(int value) {
    if (value < 0) {
        return "negative";
    } return "non-negative";
}

Both return the same thing. The second is easier to scan and stays flat when more checks are added. When there is no else and nothing after the branch, drop the braces and the nesting entirely.

12. Pattern Matching in the Condition

An if is the natural home for an instanceof pattern, which tests the type and binds the value in one step. This is final from Java 16.

Main.java
Run Online
Object payload = "hello";
if (payload instanceof String s) {
    System.out.println(s.length());
    // s is already a String, no cast needed
}

The bound variable is in scope only where the test succeeded, so the else branch is where it becomes unavailable.

Main.java
Run Online
if (payload instanceof Integer i) {
    System.out.println("never reached");
} else {
    System.out.println("i is not in scope here");
}

Combined with negation the pattern still works, because the binding is only in scope when the test is true.

Main.java
Run Online
if (!(payload instanceof String s)) {
    System.out.println("not a string");
} else {
    System.out.println("negated form, s=" + s);
}

Verified output is negated form, s=hello. The pattern composes with && as well, which is the usual way to check a type and then a property of it.

Main.java
Run Online
if (payload instanceof String s && s.length() > 3) {
    System.out.println("a string of some length: " + s);
}

13. Common Forms

A short catalogue of the shapes you will write most often, all of which are single if statements with no else.

FormUse it for
if (c) { }A single boolean test, nothing else needed
if (a && b)Both must hold, with null-safe ordering
if (a || b)Either is enough
if (!a)Inverting a flag
if (o == null)A null guard before dereferencing
if (o instanceof T t)Type test with a safe binding
if (flag != null && flag)Testing a Boolean wrapper safely
if (c) return;A guard clause that exits early

The null guard and the Boolean wrapper check are the two that most often appear in real code, and both are about avoiding a run-time failure rather than about logic.

Main.java
Run Online
if (result != null && result.size() > 0) {
} // guard, then check

14. Pitfalls and Compiler Messages

CodeWhat happens
if (1)Compile error, int cannot be converted to boolean
if (str)Compile error, String cannot be converted to boolean
if (array)Compile error, even a non-empty array is not truthy
if flag != nullUnwraps a Boolean, which is almost never what you want
if (flag) with a null BooleanNullPointerException on unboxing
Braces omittedOnly the next single statement is conditional
Braceless if plus elseThe else attaches to the inner if
Using a block variable outside itCompile error, cannot find symbol
Redeclaring an enclosing localCompile error, already defined in method
Reading a variable assigned only inside the ifCompile error, might not have been initialized
int r = if (c) 1;Compile error, an if is not an expression

The if (flag != null) line is worth calling out because it compiles, and it tests something other than what the name suggests.

Main.java
Run Online
Boolean flag = Boolean.TRUE;
if (flag != null) {
} // tests NON-NULL, not the truth of the value

A Boolean compared with != null asks whether the reference is present, not whether the value is true. A boolean primitive would not even allow this comparison, which is one more reason to prefer the primitive.

15. Cheat Sheet

QuestionAnswer
Is else requiredNo, an if alone is a complete statement
Are parentheses requiredYes
Condition typeMust be boolean
if (1)Compile error, int cannot be converted to boolean
if (str)Compile error, String cannot be converted to boolean
if (array)Compile error, arrays are not truthy
Evaluations of the conditionExactly one per execution
&& and ||Short-circuit, right side may be skipped
Braces omittedOnly the next single statement is conditional
Braceless with an elseThe else attaches to the nearest if
Block variable scopeThe braces only
Redeclaring an outer localCompile error, already defined in method
Reassigning an outer localFine, and visible after the block
Definite assignmentRequired, or the read is rejected
Is an if an expressionNo, it is a statement and yields nothing
Need a value from a testTernary or switch expression
Boolean null in a conditionNullPointerException on unboxing
Null-safe wrapper testflag != null && flag
instanceof patternStandard since Java 16, binds the value
Early returnPrefer to wrapping the rest of the method

The short version: an if runs a block when a strictly boolean condition is true, evaluates that condition once, short-circuits when you combine conditions, and always keeps its meaning only if you use braces. It cannot produce a value, so reach for a ternary when you need one.

Runnable Code Example: The Java if Statement

Java 17+
Main.java
Run Online
public class IfStatementDemo {
    public static void main(String[] args) {
        int age = 20;
        // the basic form: one condition, no else needed
        if (age >= 18) {
            System.out.println("Eligible to vote!");
            System.out.println("Welcome to active citizenship.");
        } // a false condition simply skips the block
        int score = 45;
        if (score >= 50) {
            System.out.println("This line never prints.");
        } // guard clause: exit early instead of nesting
        System.out.println(describe(120));
        System.out.println(describe(-5));
        // && and || combine conditions, and short-circuit
        String user = "admin";
        int pin = 1234;
        if (user.equals("admin") && pin == 1234) {
            System.out.println("Access granted");
        } // instanceof pattern tests the type and binds the value at once
        Object payload = "hello";
        if (payload instanceof String s) {
            System.out.println("String of length " + s.length());
        }
    } // an early return replaces an else block
    static String describe(int value) {
        if (value < 0) {
            return "negative";
        } return "non-negative";
    }
}

Common Java Technical Interview Questions & Answers

Interview Prep
Q1

What happens if curly braces are omitted after an if statement?

Only the immediately following single statement is conditional, and everything after it runs unconditionally. So with if (age >= 18) System.out.println("can vote"); followed by another println, the second line always prints. Omitting braces is legal but fragile. The real danger is not the original line, which is easy to read, but the later edit that adds a second line to a branch that had only one: that second line silently becomes unconditional. This is the same class of error as the Apple TLS goto fail bug, where a missing brace caused a security check to be skipped. Always use braces, even for one statement.
Q2

What is the best practice regarding braces with if statements?

Always use braces, even when the body is a single statement. The cost is one keystroke, and the benefit is that the grouping is explicit and cannot silently change when someone adds a line. It also makes every later edit safe by default, since the block is already there. Most Java style guides, including the common IDE defaults, require braces, and the compiler does not enforce it, so this is a convention you have to hold to yourself.
Q3

Can I use a number or a String directly in an if condition?

No. The compiler rejects it with incompatible types, since int cannot be converted to boolean, and the same for a String or an array. Java has no truthy or falsy values, unlike C and C++ where any nonzero number counts as true and a null pointer counts as false. Write if (count > 0) instead of the bare test. Beyond the compile error, the explicit form is better style because it states the intent rather than making the reader infer it. The one exception is the Boolean wrapper, which is accepted but throws a NullPointerException when it is null, because it has to be unboxed first.
Q4

How many times is the condition evaluated?

Exactly once per execution of the if. It does not get re-checked inside the block, and it does not get evaluated at all if the statement is never reached. This makes a method call with side effects safe to place in a condition, though you should be aware a method call in a loop condition is re-evaluated on every iteration. A subtlety is that combining conditions with && or || can result in more than one evaluation, since short-circuit evaluation means the right operand runs only if the left does not already settle the result. So if (check() && check()) calls check twice, while if (false && check()) calls it zero times.
Q5

What is short-circuit evaluation, and why does it matter for if?

It means && and || evaluate the right-hand operand only when it can still change the answer. So in false && rhs(), rhs is never called, and in true || rhs() it is also never called. That makes short-circuit a correctness tool rather than only a performance one. The classic use is null safety: name != null && name.isEmpty() is safe, because isEmpty is only reached when name is not null. Reversing those two operands throws a NullPointerException. The same reasoning protects you from a missing file or a slow lookup in the right-hand side.
Q6

Does an if statement produce a value?

No, an if is a statement, so it performs an action and yields nothing. You cannot write int result = if (c) 1; and the compiler rejects it with illegal start of expression, and the same applies to passing an if directly into a method call. If you need a value out of a condition, use the ternary operator, which is an expression: int result = c ? 1 : 0;. A switch expression is the other option for multi-way cases. This statement-versus-expression distinction is the main structural difference between the two and the reason an if followed by a separate assignment is such a common pattern.
Q7

Why can I not use a variable I declared inside my if block afterwards?

Because the variable's scope is the block in braces, and using it outside is a compile error reporting that the symbol cannot be found. Reassigning a variable declared outside is different and perfectly fine, and the new value is visible afterwards. Redeclaring the same name inside the block, however, is rejected with variable already defined in method, so shadowing an enclosing local is not allowed for locals. Shadowing a field is legal because fields and locals live in different namespaces, but the inner declaration then silently hides the field, so it is worth avoiding.
Q8

What is the dangling else problem?

An else always attaches to the nearest if above it that does not already have an else. When you write an if containing another if without braces, the else binds to the inner if, which is rarely what you intended. With if (a == 0) if (a == 1) ... else ..., the else belongs to the inner condition, so when a is 0 the else branch runs. This is where omitting braces stops being a readability issue and starts changing behaviour, so the rule is to use braces whenever an if and an else appear together. If you find yourself writing an else with a braceless if above it, that is the signal to add braces.
Q9

When should I prefer an early return over an if-else?

When the method has nothing left to do after the branch. Returning early from the if keeps the main path unindented and flat, which is much easier to scan, and it stays readable as more checks are added. The wrapped version, where the main work sits inside an else block, adds an indentation level that carries no information. Guard clauses also let you handle the exceptional or invalid cases first and leave the happy path at the end, which reads top to bottom. When there is no else and nothing after the block, you can drop the braces and the nesting entirely.
Q10

What is pattern matching for instanceof, and does it work in an if?

It is final from Java 16 and works naturally in an if. Instead of testing the type and then casting, you bind the value in the test itself: if (o instanceof String s) gives you s as a String with no cast needed. The variable is in scope only where the test succeeded, so it is unavailable in the else branch, which is exactly the safety the old two-step version lacked. It composes with && for a type plus content check, and it also works under negation, since the binding is present only where the test is true. Note this is separate from pattern matching in switch, which is a newer feature that is standard in Java 21 but still preview on 17.
Q11

What does if (flag != null) actually test when flag is a Boolean?

It tests whether the reference is present, not whether the value is true, so with flag set to Boolean.FALSE the condition is still true. This compiles and it is a genuine trap, because the name suggests a truth test but the operation is a reference comparison. A boolean primitive would not even allow this comparison, which is one more reason to prefer the primitive type. To test the value safely, use flag != null && flag, which checks for null first and only then unboxes, so it is short-circuit safe. Remember that plain if (flag) on a null Boolean throws a NullPointerException instead.
Q12

What are the most common mistakes with the if statement?

Using a non-boolean condition, which is a compile error in Java rather than a silent coercion. Omitting braces, which is legal but lets a later edit change behaviour silently, especially when an else is involved and binds to the wrong if. Testing a Boolean wrapper that may be null, which throws a NullPointerException on unboxing, and comparing it with != null when you meant to test its value. Expecting an if to produce a value, which is a compile error since if is a statement. Reading a variable assigned only inside the if, which definite assignment rejects. And reusing a name from the enclosing method inside the block, which is rejected as already defined in method.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Always use braces around the body of an if, even when it is a single statement, because the grouping is explicit and a later edit cannot silently move a line out of the branch; the omission is also what turns an else into a dangling one that binds to the inner if. Make the condition a strictly boolean expression, and write comparisons like count > 0 rather than relying on a bare value, since Java has no truthy or falsy values and the explicit form also documents the intent. When a condition may be a null Boolean, test it with flag != null && flag, because the ordering matters and a plain if (flag) throws a NullPointerException on unboxing; prefer a primitive boolean where you can. Keep side effects out of the condition unless they are the condition, and remember that the condition is evaluated exactly once but a loop condition is re-evaluated on every iteration. Rely on short-circuit evaluation deliberately, ordering && operands so the left side rules out a failure on the right, which is what makes a null guard safe, and never reversing that order. Declare variables where they are used rather than at the top of the method, and do not try to redeclare an enclosing local inside the block, since the compiler rejects it; reassign the existing variable instead, and keep the new name when it means something different. Prefer an early return to wrapping the rest of a method in an else, because the unindented main path stays readable as more checks are added. Use instanceof pattern matching where you would otherwise test a type and then cast, since it binds the value in the condition and keeps it out of scope where the test failed. If you need a value out of a condition rather than an action, use a ternary or a switch expression, since an if is a statement and cannot be assigned from.
We value your privacy & transparency

OperateTools uses cookies and local storage to ensure basic tool functionality, preserve preferences, and analyze aggregated traffic. We never sell your personal data or index your document files. Learn more in our Privacy Policy.