1.1-Introductie-Programmeren

Scoping demo

Scope has to do with the accessibility of the variable in the program. Where can the variable be accessed and used?

Step 1: Simple class with brackets

public class ScopingDemo implements Runnable {
    
}

Step 2: Method declaring a variable (local variable scoping)

public class ScopingDemo implements Runnable {

    public void run() {
        int age = 18;
    }
}

A variable is created (declared and initialized) inside a method and is therefore only avaiable within the run() method (more precise: after the declaration itself)

Step 3: Smaller scopes

It is possible to define an even smaller scopes.

public class ScopingDemo implements Runnable {

    public void run() {
        int age = 18;

        for (int i = 0; i < 10 ; i++) {
            SaxionApp.printLine(i);
        }

        SaxionApp.printLine("Variable `i` is NOT available here!");
    }
}

Note: that i is declared in the for loop. This makes i only available in the body of the for-loop. If you want i to have broader scope. Move it up.

public class ScopingDemo implements Runnable {

    public void run() {
        int age = 18;

        int i;
        for (i = 0; i < 10 ; i++) {
            SaxionApp.printLine(i);
        }
        SaxionApp.printLine("Variable 'i' IS available here");
    }
}

(Note: i is not a very desciptive name, fine to use in a for loop as index, but not outside.) This works the same for other scope blocks { } as well. Examples if statements, switch statements, while loops and enhanced for-loops. See below a while-loop example.

public class ScopingDemo implements Runnable {

    public void run() {
        int counter = 0;
        while (counter < 10) {
            int counterPlus10 = counter + 10;
            counter++;
        }
        SaxionApp.printLine("Variable counter is available here, but counterPlus10 is  NOT");
    }
}

Step 4: A broader scope

public class ScopingDemo implements Runnable {

    public void run() {
        int age = 18;
    }

    public void print() {
        SaxionApp.printLine(age);
    }
}

So, this program does not compile, since age is declared in the run() method and is only available there. What if you want to make the value of age available in the print() method as well, you have 2 options:

1) Pass the variable as a argument to the print() method. (called: parameter scoping)

public class ScopingDemo implements Runnable{

    public void run() {
        int age = 18;
        print(age);
    }

    public void print(int ageParameter) {
        SaxionApp.printLine(ageParameter);
    }
}

2) Declare age on class level (called: instance variable scoping)

public class ScopingDemo implements Runnable{
    int age = 10;

    public void run() {
        
        SaxionApp.printLine(age); // prints: 10
        age = 20; // age is set to 20
        
        print(); 
    }

    public void print() {
        SaxionApp.printLine(age); // prints: 20 
    }
}

This works perfectly fine. You can print age, or change its value from all methods in the class.

Step 5: Updating primitive values in a method

public class ScopingDemo implements Runnable {

    public void run() {
        int age = 10;
        printAndUpdateAge(age);
        SaxionApp.printLine(age); // (still) prints 10
    }

    public void printAndUpdateAge(int age) {
        age++; // Set local age to: 11
        SaxionApp.printLine(age); // prints: 11
    }
}

Note: that since age is a primitive-type (type with small letter) a copy is passed to the method printAndUpdateAge(). The copied value is changed in the method printAndUpdateAge(), but not the original value.

Step 6: Updating ArrayLists from a method

For non-primitive types, like ArrayLists this works completely different. When passing an ArrayList as an argument to a method, the reference is passed and not a copy of the value. This means that:

public class ScopingDemo implements Runnable {

    public void run() {
        ArrayList<String> names = new ArrayList<>();
        names.add("Alpha");

        addNameToList(names);

        SaxionApp.printLine(names); // [ Alpha, Bravo] is printed.
    }

    public void addNameToList(ArrayList<String> names) {
        names.add("Bravo");
    }
}

Both methods can manipulate the same list.

If you need the information from the list in many methods, you might decide to declare it as an instance variable again. See the sample below:

public class ScopingDemo implements Runnable {
    ArrayList<String> names = new ArrayList<>();
    
    public void run() {
        names.add("Alpha");
    }

    public void addBravo() {
        names.add("Bravo");
    }

    public void addCharlie() {
        names.add("Charlie");
    }

    public void print() {
        for (String name: names) {
            SaxionApp.print(name); 
        }
    }
}

All methods work on the same list, so this is perfectly possible and saves the trouble of passing the same list as method parameter each time.

To summarize:

Instance variable level scoping:

Local variable scoping (on method level):

Parameter level scoping:

public class ScopingDemo implements Runnable {
    
    public void run() {
        ArrayList<String> names = new ArrayList<>();
        int age = 10;
        update(names, age);
    }

    public void update(ArrayList<String> names, int age) {
        names.add("Alpha"); // changes the list in run() also
        age++; // only changes the local copy of age here
    }
}