33

I received a compilation error for the following code:

if(true)
    int a = 10;
else
    int b = 20;

If I change it to the following code, then there is no compilation error:

if(true) {
    int a = 10;
}
else {
    int b = 20;
}

Why is the first syntax wrong, and from what language standard?

11
  • 1
    After doing some testing, it seems JVM doesn't like having variable declarations inside an if-else without braces. I'm sure someone could go more in-depth with this, but my guess is the scope can't be resolved. System.out.println() works without braces. Commented Dec 23, 2014 at 16:43
  • 3
    @DrewKennedy It wouldn't be so crazy if declaring variables inside if-else without braces isn't allowed. You're setting a variable which you can never use. Commented Dec 23, 2014 at 16:46
  • 3
    @Daniel I was just thinking that too. If you're allowed only one line of code after the if, declaring a variable wouldn't make sense. Commented Dec 23, 2014 at 16:48
  • 1
    @almasshaikh: This isn't looking like a dupe. It may be similar, but it'd make sense to keep the semantics of if and for distinct. Commented Dec 23, 2014 at 16:58
  • 1
    @Daniel, that's because JavaScript has no block scope and applies variable hoisting. adequatelygood.com/JavaScript-Scoping-and-Hoisting.html Commented Dec 23, 2014 at 18:27

5 Answers 5

27

The Java specification says that an if-then-else statement is of the following form:

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

Where Statement and StatementNoShortIf can be various things including blocks (code surrounded with braces), assignments (to already declared variables), other if statements etc.

Of note is that declaration statements (e.g. int a; or int a = 10;) are missing from that list, thus you get a compilation error.

For the full list, you can read the Java specification here: http://docs.oracle.com/javase/specs/

Sign up to request clarification or add additional context in comments.

5 Comments

This should be enough to answer the question, just a little bit surprise for a c++ programmer with this kind of error.
And with the answer in 'A single-line loop with a mandatory pair of braces in Java' should make it clear enough to the question.
What does NoShortIf refer to?
@Navin The NoShortIf is to prevent situation with nested if statements where a reader of the code cannot easily decide (or might get confused) to which if an else branch belongs to. This is explained in section 14.5 of the Java Language Specification
@MarkRotteveel Nifty!
20

Lets analyze what your first code example would mean for the language design

if(condition)
    int a = 10;
else
    int b = 20;

Either it means that depending on the condition we have defined a or b. As we don't know which branch was taken, how do we use either a or b after the if-statement? We can't (and if we could that would probably result in strange bugs).

So as language designers we decide that a and b are not visible outside their respective branches to avoid these weird bugs. But as a block-less branch can only have a single statement, we have declared a (or b) only to be immediately unreachable/unusable again, so doing that makes no sense. Therefor we decide that a variable declaration is only allowed with a block. A block can have multiple statements, so variables declared in that block can be used by those other statements.

The designers of Java probably applied similar reasoning, so they decided to only allow declaration in a block. This is done through the definition of if (JLS 14.9):

IfThenStatement:
    if ( Expression ) Statement

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

IfThenElseStatementNoShortIf:
    if ( Expression ) StatementNoShortIf else StatementNoShortIf

Statement (JLS 14.5)

Statement:
    StatementWithoutTrailingSubstatement
    ...

StatementNoShortIf:
    StatementWithoutTrailingSubstatement
    ...

StatementWithoutTrailingSubstatement:
    Block
    ...

Block (JLS 14.2):

Block:
    { [BlockStatements] }

BlockStatements:
    BlockStatement {BlockStatement}

BlockStatement:
    LocalVariableDeclarationStatement
    ClassDeclaration
    Statement

And LocalVariableDeclarationStatement (JLS 14.4), which repeats that it can only occur within a immediately enclosing block:

Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.

Comments

13

JLS-14.4. Local Variable Declaration Statements reads (in part),

Every local variable declaration statement is immediately contained by a block.

And

JLS-14.9. If Statmenets

Otherwise, execution continues by making a choice based on the resulting value:

If the value is true, then the contained Statement is executed; the if-then statement completes normally if and only if execution of the Statement completes normally.

If the value is false, no further action is taken and the if-then statement completes normally.

However, JLS-14.5. Statements doesn't include variable declaration.

Defining two different variables within the scope of a single-statement block (containing just the variable definitions) makes them both unreachable. I think you'd have better luck with a ternary expression

int a = (condition) ? 10 : 20;

or

int a;
if (condition)
    a = 10;
else
    a = 20;

or

int a;
if (condition) {
    a = 10;
} else {
    a = 20;
}

Note that the variable a is then initialized to a value based on the condition and it is reachable after that statement.

8 Comments

I disagree with your assessment "So your first example creates a block for int a which terminates the if block (and thus your else has no matching if)." The reason is the definition of statement and block in the JLS
@MarkRotteveel is right. The error has nothing to do with the else. If you take out the else part you still get an error.
@Mark Edited. Thanks for your input, do you think it reads better now?
And if it were allowed, how would you reach it? Hence, I think, why it isn't allowed.
I removed my earlier comment, you are entirely right with your last edit; I was approaching it too much from the syntax point of view, and not from the reasons for that syntax.
|
6

Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.

Read this http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.4

5 Comments

Except that the second version does compile
@JuanMendes The second version is immediately contained in a block.
yes that is the reason
@MarkRotteveel I guess my question is: Isn't the first one also contained by a block (outside of the if)?
@JuanMendes No, not immediately. See the answer by Elliot Frisch or my answer, which describe it in more detail
0

My best guess is that you cannot declare variables conditionally.

  • When you don't have braces, you're trying to declare a variable conditionally in the outer scope, that's not allowed.
  • When you add the braces, you're creating the variables in that local scope (which are not allowed to be used outside of those braces)

5 Comments

I know this is probably not accurate, I'd love for someone to explain what the problem with the answer is.
this answer is helpful to me.
I think your guess is just.... you know... a guess. Other answers provide documentation and the exact 'why' of this behaviour.
@AlessandroDaRugna And your comment did not explain what the actual problem was. The answers that are here are extremely technical, I've written a layman's explanation as to why the designers of Java may have chosen to implement it this way.
@Juan You have expressed your opinion instead of answering the question. You are probably right and I agree with you, but this isn't the answer the OP was looking for.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.