Logout

Home Topic 4 Last Next

Scope of Variables

Variables are only accessible within the block of code in which they were declared - which includes blocks made within that block.

Consider the following code:

12 public class ScopeMain {
13
14     static double f = 8.9; // f declared within the class, so available everywhere in the class; i.e. "global scope"
15     public static void main(String[] args) {
19         double g = 7.3; // g declared within the main method, so available only within the main method.
20
21         scopeMethodWorks();
22         methodWithAScoopeProblem();
34     }
36        
38     private static void scopeMethodWorks(){
39         double d = 3.2;
40         double e = 4.3;
41         System.out.println("d + e + f = " +  (d + e + f)); //d and e and f are all in scope.
43     }
44 
45     private static void methodWithAScopeProblem(){
46         double h = 34.2;
47         double i = 32.2;
48         System.out.println("h + i + g = " + (h + i + g)); // h and i are in scope, but g is not in scope.
49         //SO THIS WOULD BE AN ERROR.
50     }
51 }

So above, line 41 works since all three variables are within scope. Variables d and e are obviously declared with the same block in which they are used. And variable f is Ok to use, sinec it was declared in the block in which the method nested within. Put another way method scopeMethodWorks() is within the ScopeMain class block, where f was declared, so scopeMethodWorks() can access f.

But at line 48 there is a problem. The println is trying to access g, but g was not declared with the method itself, nor with the block in which it is nested, the ScopeMain class block. Rather, g was declared inside the main method, and methodWithScopeProblem() is not nested within the main method.


The Reason for Limited Scope

The main reason for scope being limited to the block where a variable is declared (as well as the blocks nested within), rather than being accessible throughout the program is memory management. In fact, memory management is the reason for very many things in programming. It is simply a waste for variables to remain in memory after they are needed. This may not be so big a deal if your talking about a computer with a couple of Gigabytes of RAM memory, it is more important for smaller devices with less RAM memory. But even with loads of RAM, why take up memory that you don't need to once you are finished with a certain variable? So variables are declared within the block in which they are used, and "garbage collected" when that block is ended. You'll also note that declaring variables only just before they are used makes sense anyway.

Garbage Collection

There is no use having variables take up valuable computer memory once they are no longer needed. Therefore Java "garbage collects" variables when the execution of the code reaches the end of a block where a variable was defined.

Take the following code as an example.

 5 public class Main {
 6 
 7     public static void main(String[] args) {
 8         int x = 10;
 9         int y = 20;
10         if(true){ //you would never go if(true), but this just gives us an extra internal block of code, for instructional purposes.
11             int z = 30;
13             System.out.println("X is " + x);
14             System.out.println("Y is " + y);
15             System.out.println("Z is " + z);
16         } //z is garbage collected
17         System.out.println("X is " + x);
18         System.out.println("Y is " + y);
19         System.out.println("Z is " + z);  //This is where the problem is since z  is out of scope; 
20                                          //indeed, it has actually alrady been garbage collected above in line 17.
20     } //x and y are garbage collected.
22 }

Variables x and y are declared within the main() block, so they are "alive" from where they are declared, at lines 7 and 8, up to line 19. But at line 20 they are garbage collected.

But z is declared inside the if block. So it is only "alive" from lines 11 to 15, and is garbage collected at line 16.

Note that it's not directly because of garbage collection that scope can be an issue. Consider variable g in the first example. Variable g is still "alive" when the attempt is made at line 48 to use it, but it cannot be because it is not in scope of that method (as described above). Rather, scope rules are a requirment of the garbage collection memory management system. Since variables are to be ultimately garbage collected when blocks are ended, there have to be rules to determine when and where variables can be expected to be available. In fact, the example above shows would could happen, given the reality of garbage collection, if scope rules did not exist. In this case not only is variable z out of scope, it also so happens that it does not even exist any more, as it has been garbage collected.

So consider the following example that could be from one of your "Personality" programs.

10  public static void main(String[] args){  
11      if(multimediaUser || lotsOfMoney){
12       .
13       .
14       .
25           System.out.println("How many years old is your coputer?");
26           int yearsOld = Integer.parseInt(br.readLine());
27       } //yearsOld garbage collected, since declared in this block
28       .
29       .
30       .
31       if(likeMac && yearsOld > 5){ //problem: yearsOld is out of scope (and actually has already been garbage collected).
32           System.out.println("You should consider getting a new Mac computer.");
33       }
34   }   

The above won't work, since yearOld was declared in a block of code that has already been closed out. So the solution is to declare the yearsOld variable outsied of both blocks where it will be used, as follows:

10  public static void main(String[] args){  
11       .
12       .
13       . 
23       int yearsOld = -999;
24       if(multimediaUser || lotsOfMoney){
25           System.out.println("How many years old is your coputer?");
26           yearsOld = Integer.parseInt(br.readLine());
27       }
28       .
29       .
30       .
31       if(likeMac && yearsOld > 5){
32           System.out.println("You should consider getting a new Mac computer.");
33       }
34  }  //yearsOld garbage collected here now.

Now we're Ok, since yearsOld won't be garbage collected before being used both times.

Scope Problems General Solution

The solution to solving scope issues is to declare the variable in the same block where it is defined. Often this means declaring it above where you just tried to use it. When declaring it another place, just remember that you can't declare a variable twice in the same scope. So if you had, for example:

...
if(true){
int x = 3;
}
x++;

Well, that wouldn't work since x is garbage collected before it is used in the last line. But don't only add the initialization above, but also take away the int from where x is assigned, within the for block, like this:

...
int x = -999;
if(true){
x = 3;
}
x++;


Another (longer) Example

Problem:

 5 package flow.of.control;
 6 
 7 import java.io.BufferedReader;
 8 import java.io.InputStreamReader;
 9 
10 /**
11  *
12  * @author John Rayworth
13  */
14 public class ScopeAlso {
15 
16     static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
17 
18     public static void main(String[] args) {
19         try {
20             
21             int numTries = 0;
22             boolean passwordCorrect = false;
23             do {
24                 System.out.println("What is the password?");
25                 String password = br.readLine();
26                 if(password.equals("abcd")){
27                     passwordCorrect = true;
28                 }
29 
30             } while (!password.equals("abcd") && numTries < 3);
31             //problem above: password garbage collected just before this.
32             
33             if(passwordCorrect){
34                 bankAccountMethod();
35             }
36         } catch (Exception e) {
37             System.out.println("Error in the main method.");
38         }
39 
40     }
41     public static void bankAccountMethod(){
42         
43     }
44 }

Solution:

 5 package flow.of.control;
 6 
 7 import java.io.BufferedReader;
 8 import java.io.InputStreamReader;
 9 
10 /**
11  *
12  * @author John Rayworth
13  */
14 public class ScopeAlso {
15 
16     static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
17 
18     public static void main(String[] args) {
19         try {
20             
21             int numTries = 0;
22             boolean passwordCorrect = false;
23             do {
24                 System.out.println("What is the password?");
25                 String password = br.readLine();
26                 if(password.equals("abcd")){
27                     passwordCorrect = true;
28                 }
29 
30             } while (passwordCorrect && numTries < 3);
31             //One solution (used here) is to use the passwordCorrect variable which is declared within the try block.
               //The other solution would be to declare password outside the do/while, where the other two try block variables are declared.
32             
33             if(passwordCorrect){
34                 bankAccountMethod();
35             }
36         } catch (Exception e) {
37             System.out.println("Error in the main method.");
38         }
39 
40     }
41     public static void bankAccountMethod(){
42         
43     }
44 }