简体   繁体   中英

Variable Declared Outside of For Loop Vs Inside

//assume there is a java class call Node, and node is an array of Node

for(Node i: node){
    Node j = i;
}

Node j;
for(Node i: node){
    j = i; 
}

Can someone please explain essentially what's the difference between this two?

Node j; on its own isn't 'code', in the sense that it results in zero bytecode - it does nothing on its own. It's a 'declaration'. It's an instruction to the compiler.

You're telling the compiler: There is this thing; I shall call it j , and it is a local variable. Please fail my compilation unless you can 100% ensure that this variable only ever holds either null or " reference to an object whose actual type is either Node or some subtype of Node ". It decline to assign something to this variable right now; please fail to compile if I attempt to access it before you can 100% guarantee that some code has already ran that definitely assigned it first.

That's a ton of instructions for the compiler and absolutely none of it requires any code right then and there - it's just instructions for what to do in other lines of code - for example, in your second snippet, without that Node j; at the top, j = i; is not something that the compiler can do for you. It has no idea what you intend to do there; it does not know what j is, you did not inform the compiler about it, and in java, the language spec indicates that you can't just make up variable names without first telling the compiler about them.

Thus, bytecode wise, the exact difference between your 2 specific snippets here is nothing - local variables are a figment of javac's imagination: As a concept, 'local variable' doesn't exist, at all, at the JVM/bytecode level: It's just 'slots' in the local frame (ie local variables have a number, not a name), or on-stack space.

In other words, to figure out what the difference might be, it's entirely a matter of answering the question: How does javac interpret these 2 snippets? Because bytecode wise there is not going to be any difference, ever. Node j; simply cannot be bytecode - there is no such thing as a 'local variable' there, after all.

The only crucial difference is that any given local variable declaration (such as Node j; ) declares its existence for a certain scope: It says: "There is this thing called j for these specific lines and not for any others". That scope is simply the next nearest pair of braces. So, in:

void foo() {
  Node j;
  for(Node i: node){
      j = i; 
  }
}

You have declared that there is one local variable named j , and this applies to the entire foo() method (given that those are the nearest pair of braces when you look 'outwards' from your Node j; declaration.

Whereas with:

void foo() {
  for(Node i: node){
      Node j = i; 
  }
}

The 'scope' of your j declaration is that for loop - after all, that's the 'nearest pair'. In other words, this is almost legal:

void foo() {
  Node j;
  for(Node i: node){
      j = i; 
  }
  System.out.println(j);
}

Except for one tiny little detail: The compiler cannot 100% guarantee that j is actually assigned when we get to the println line - after all, what if your node collection is actually empty? Then j = i; ran zero times. So if you try to compile the above, the compiler will actually refuse, saying j is not definitely assigned . But make that Node j = null; and the above code would compile and run. In contrast to:

void foo() {
  for(Node i: node){
      Node j = i; 
  }
  System.out.println(j);
}

This one doesn't compile with the error j? What are you talking about j? What are you talking about - the j you declared here only applies to all lines within the {} that goes with the for loop, thus, the mentioning of j in the println line is mentioning an unknown thing, and thus the compiler will complain about it in those terms: What is j ?

So what do I do?

Follow conventions: When in rome, act like romans. When programming java, write it the way the vast majority of java coders would. Which means: Declare local variables at the latest possible point, at the right scope level. Thus, something like:

void foo() {
  System.out.println("Starting method");

  Node lastVisited = null;
  for (Node i : nodes) {
    lastVisited = i;
  }
  System.out.println("Last visited: " + lastVisited);
}
  • Don't declare lastVisited at the top of the method.
  • Do declare it before the for loop as we need it outside of it.
  • Names are important.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM