6
public class Test{
   public void newMethod(){

      if(true)int i=0;

   }
}

The above code gives me the following error

Test.java:4: error: '.class' expected
      if(true)int i=0;
                  ^

But if I write it like this

public class Test{
   public void newMethod(){

      if(true){
         int i=0;
      }

   }
}

then there is no error!

I know this question isn't helpful to the community, but I'm really curious why I need to have brackets in this statement. I've been programming in java for a few years and I've only encountered this error just now.

I'm using JGrasp by the way.

Sergey Orshanskiy
  • 6,794
  • 1
  • 46
  • 50
TonyTerminator
  • 119
  • 2
  • 8
  • 2
    always use brackets... – Black Sheep Oct 09 '13 at 18:21
  • 8
    I'm not a Java programmer, but I presume because the single-statement version of `if` does not allow variable declarations. And why should it, since nothing will ever be able to use that variable? – Dark Falcon Oct 09 '13 at 18:22
  • That actually makes a lot of sense! I don't know how I overlooked that. – TonyTerminator Oct 09 '13 at 18:25
  • 1
    While it makes a lot of sense, I was under the impression that just about anywhere you could put a statement, a declaration was just as legal... This is kinda weirding me out. >_ – user Oct 09 '13 at 18:28
  • I’m actually more surprised about that error message. Can anyone check what a normal Java says when trying to do this? I don’t have an SDK around right now. – poke Oct 09 '13 at 18:35
  • While that would make sense, I would expect the error to be "unused variable at...". – BergQuester Oct 09 '13 at 18:38
  • and to confirm Dark Falcon answer you can create the variable first and then assign the value int x; if(true)x=0; which make sense because now the variable will be useful. – Goca Oct 09 '13 at 18:47
  • 1
    @poke `javac` (1.7.0_17) produces 4 errors on that line, the first of which is the OP's error message. The second is "not a statement", then "Illegal start of expression", and finally ';' expected. – Ian McLaird Oct 09 '13 at 18:57
  • The first language I learned was Turbo Pascal. There you only had variable declarations in the beginning of a program. In Java nowadays we can have them directly inside any `{ ... }` block, but not just anywhere you want. Just think of `{ ... }` blocks in terms of scoping variables rather than merely in terms of grouping operations. `{ statement }` is not quite identical to `statement` any more. – Sergey Orshanskiy Oct 09 '13 at 19:07

2 Answers2

7

Here is my understanding. Quoting from Chapter 14 of JAVA SE 7 specification:

14.2. Blocks

A block is a sequence of statements, local class declarations, and local variable declaration statements within braces.

Block:
    { BlockStatementsopt }

........     

BlockStatement:
    LocalVariableDeclarationStatement
    ClassDeclaration
    Statement

So a block is always in braces { ... }.

14.4. Local Variable Declaration Statements

A local variable declaration statement declares one or more local variable names.

LocalVariableDeclarationStatement:
    LocalVariableDeclaration ;

LocalVariableDeclaration:
    VariableModifiersopt Type VariableDeclarators

.......

VariableDeclarator:
    VariableDeclaratorId
    VariableDeclaratorId = VariableInitializer

.......

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.

Now, what does it mean, "immediately contained"?

Some statements contain other statements as part of their structure; such other statements are substatements of the statement. We say that statement S immediately contains statement U if there is no statement T different from S and U such that S contains T and T contains U. In the same manner, some statements contain expressions (§15) as part of their structure.

Let's look at your example:

public class Test{
   public void newMethod(){

      if(true)int i=0;

   }
}

In this case we have the following block:

{

          if(true)int i=0;

}

Inside this block we have an If Statement:

if(true)int i=0;

This statement, in turn, contains a local variable declaration:

int i=0;

Therefore, the condition is violated. Recall: Every local variable declaration statement is immediately contained by a block. However, in this case the local variable declaration is contained by an If statement, which is not a block itself, but is contained by another block. Hence this code would not compile.

The only exception is for a for loop:

A local variable declaration can also appear in the header of a for statement (§14.14). In this case it is executed in the same manner as if it were part of a local variable declaration statement.

(You may need to reread it a few times to understand.)

Sergey Orshanskiy
  • 6,794
  • 1
  • 46
  • 50
  • I think you should actually start at [14.9: The if statement](http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.9) and see that the allowed thing to follow an if is a `Statement`. Statements are defined in [14.5](http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.5) and do not explicitely contain any variable declaration. The only contains single more specific statements (things you expect here) and `Block` which would be defined as you explained before and is the only place where variable declarations can be placed. – poke Oct 09 '13 at 19:43
  • @poke: yes, but 14.4 is called "Local Variable Declaration Statements", which is somewhat confusing, even though 14.5 does not list local variable declarations among statements. – Sergey Orshanskiy Oct 09 '13 at 19:52
1

Dark Falcon is right, if a single statement following an if test is a variable declaration then nothing can use that variable, the declaration would be limited in scope to the body of the if consequent, which would be useless, because anything following that would not have i in scope.

If if (true)int i = 0; actually worked (meaning the declaration was visible to succeeding lines), that would mean that whether you had a variable declared would depend on the result of the if test, which would not be good.

BTW, if (true) int i = 0; causes this syntax error in Eclipse:

Multiple markers at this line
    - i cannot be resolved to a variable
    - Syntax error on token "int", delete 

while putting the brackets around it compiles, although it generates a warning:

the value of the local variable i is not used
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
  • I wonder why the developers thought to include that as an error though. – TonyTerminator Oct 09 '13 at 18:48
  • @TonyTerminator: they were very thorough. Maybe they'd written code generators that created nonsensical code and wanted to trap as many errors as possible. – Nathan Hughes Oct 09 '13 at 18:51
  • 1
    @TonyTerminator: this way they had to do less work. Every time you declare a variable, it involves memory allocation, scoping change, etc. They made a decision to only allow variable declarations directly inside `{ }` blocks. After all, allowing it in other places is not that helpful, as other people already pointed out, and the stricter and more concise is the grammar, the easier it is to learn and the fewer bugs you will make. They were trying to improve on C++ with its limitless capabilities by making Java more reliable and more predictable. Yes, they ended up changing some semantics... – Sergey Orshanskiy Oct 09 '13 at 19:04