Transcripted Summary

Now that our classes are getting bigger, we have to talk about the scope of a variable.

Variable Scope

A variable is only available within the scope that it was declared within.

I'm going to demonstrate this in our next example where we're going to do an instant credit check.



We're going to approve anyone who makes more than $25,000 and has a credit score of 700 or better.

We have a new class here, InstantCreditCheck, and we have our main method,

package chapter5;

/*
 * VARIABLE SCOPE
 * Write an 'instant credit check' program that approves
 * anyone who makes more than $25,000 and has a credit score
 * of 700 or better. Reject all others.
 */
public class InstantCreditCheck {

    public static void main(String args[]){

    }
}

So, let's go ahead and think about our design.

We're going to:

  • Initialize what we know
  • Get what we don’t know
  • Check if the user is qualified
  • Notify the user

These are the steps that we need to do.

So, what do we know?

Well, we know that the required salary is $25,000 and we know that the required credit score is 700.

public static void main(String args[]){
    int requiredSalary = 25000;
    int requiredCreditScore = 700;
}

Okay. What don't we know? Well, we don't know how much their actual salary is or their actual credit score, so we need to figure that part out.

Throughout the course, we've been putting everything in the main method, but now, we're learning a bit more, and so we're going to do more advanced things like break our task up into different methods.

To get what we don't know, let's create a new method that will get the form data.

So, let's make this public static. It won't return anything. We just want it to get the input. What this will do is prompt the user and get their information.

public static void getFormData(){
    System.out.println("Enter your salary:");
    Scanner scanner = new Scanner(System.in);
    double salary = scanner.nextDouble();

    System.out.println("Enter your credit score:");
    int creditScore = scanner.nextInt();

scanner.close();
}

Even though we have this method and it's getting this information, we have to call it in order for these statements to execute.

So, from our main method, we're going to make a call: getFormData();

public static void main(String args[]){
    
    int requiredSalary = 25000;
    int requiredCreditScore = 700;

    getFormData();
}

public static void getFormData(){

    System.out.println("Enter your salary:");
    Scanner scanner = new Scanner(System.in);
    double salary = scanner.nextDouble();

    System.out.println("Enter your credit score:");
    int creditScore = scanner.nextInt();

    scanner.close();
}

Next, we need to check if the user is qualified or not.

Tip

Most of the time, when I write a method, I first write where I'm going to call it from just so that I don't forget. Because just now, we wrote this method, and if we wouldn't have remembered to call it, it would never get executed.

So, I go ahead and make the call:

public static void main(String args[]){

    int requiredSalary = 25000;
    int requiredCreditScore = 700;

    getFormData();

    //Check if the user is qualified
    isUserQualified();
}

Then it will be red to let me know that the method doesn't exist, and I fix that by creating it.

This is going to return a boolean, and we'll write:

public static boolean isUserQualified(){

}

Inside of isUserQualified, it needs to check to see if they have a qualifying salary and credit score.

So, we can use an if statement here.

public static boolean isUserQualified(int creditScore, double salary){

    if(creditScore >= requiredCreditScore && salary >= requiredSalary){

    }
}

Now, notice. All of a sudden, these variables are in red, even though we've clearly declared them here in this program.



Variable Scope

Variables are only valid within the scope in which they were defined. And by scope, you can think of it as these curly braces. The immediate curly braces that a variable was declared in is the limit to where it can be utilized.

So, salary and this creditScore can only be used inside of the getFormData method; and this requiredSalary and requiredCreditScore can only be used within the scope of the main method.

In order to use these in various scopes, we have to either pass them to the methods that need them or declare them at a higher scope.

requiredSalary and requiredCreditScore can be defined a little bit higher. So, instead of declaring them within the main method, we're going to declare them at the class level.

public class InstantCreditCheck {

    int requiredSalary = 25000;
    int requiredCreditScore = 700;

    public static void main(String args[]){

Notice, now these are between the curly braces of the class itself — meaning, they belong to the class and their scope is anything within the class. So, every single method in here is able to access these variables.

But because these methods are static, we are going to also need to declare the variables as static as well.

public class InstantCreditCheck {

    static int requiredSalary = 25000;
    static int requiredCreditScore = 700;

Now, we see that the isUserQualified method knows what requiredCreditScore is as well as requiredSalary.



But it still doesn't know salary and creditScore. That’s because these were defined in getFormData().

Now, we could possibly pass it from that method to this method. However, this is not the method that's calling this method. It's the main method that's calling this method, and the main method does not have access to salary or creditScore because it's limited to this scope of getFormData().

So, what we can do is we can return this stuff back to the main method so that the main method could then pass it on to the isUserQualified method.

However, remember, a method can only return one value, and in this case, we have two.

That's an indicator that our method is doing too much, so instead of having getFormData(), we can break this into two separate tasks of getSalary() and getCreditScore() and have each of these return information.

So getSalary() is going to return a double.

Let’s cut the statements that get and receive the salary out of getFormData() and paste them into our new method.

public static double getSalary(){
    System.out.println("Enter your salary:");
    double salary = scanner.nextDouble();
}

Then notice we have a little red here. Why? The arrow right here says it's missing the return statement. Remember, if you specify that you're going to return something, you must do so.



public static double getSalary(){
    System.out.println("Enter your salary:");
    double salary = scanner.nextDouble();
    return salary;
}

Now, we want to get the other piece of information, the credit score.

This is an int data type that should be returned. And then we can cut the credit score statements from getFormData() and we can place it inside of our new method getCreditScore(), and then return the credit score.



Now, we have a couple of errors here. This scanner is red, and the error is saying that it cannot resolve this symbol — meaning, it doesn't know what it is.

Why? Because scanner was defined within getSalary(), so this is out of scope.

Since we need the scanner in more than one method, we can also make this global, and now we're able to use it in both methods.

Now, a method itself never knows who's going to call them and when it's going to call them.

So, we couldn't take this scanner.close and put it inside of getSalary() because if anyone called getSalary() before they called getCreditScore(), then the scanner will be closed and unable to be used.

We have to leave this up to the main method — the main method is the one that's driving the flow, so it's going to call those methods to get the data, and then we'll have it close the scanner.

This getFormData(), we no longer need, so we'll change that to getSalary() and then getCreditScore().

public class InstantCreditCheck {

    static int requiredSalary = 25000;
    static int requiredCreditScore = 700;
    static Scanner scanner = new Scanner(System.in);

    public static void main(String args[]){

        getSalary();
        getCreditScore();
        scanner.close();

So main method is driving the flow. It says, I'm going to get the salary, I'm going to get the credit score, and then I'm going to close the scanner.

Now, it needs to call this isUserQualified, and we still haven't taken care of these two variables: creditScore and salary

These variables are being returned from other methods, so when we call these methods from main, they are going to return us some information, and we can store it in a variable.

double salary = getSalary(); and int creditScore = getCreditScore();

public class InstantCreditCheck {

    static int requiredSalary = 25000;
    static int requiredCreditScore = 700;
    static Scanner scanner = new Scanner(System.in);

    public static void main(String args[]){

        double salary = getSalary();
        int creditScore = getCreditScore();
        scanner.close();
    }

The data type that getSalary() is returned in is a double, so we have to declare this as a double as well. If we declared it as anything else, we would get an error saying, "incompatible types” — It required an int for this variable, however, it was being returned back as a double. So, this must match what's being returned from the method.

Now that we have those two variables, we can pass them into isUserQualified(). However, isUserQualified() doesn't specify that it has any parameter list.

So, if we want to have a method specify that data should be given to it, again, we have to put that inside of this parameter list definition. We say if you're going to call us, you must pass us a credit score and you must pass us a salary.

public static boolean isUserQualified(int creditScore, double salary){

Parameters within a method heading are essentially variable declarations for that method.

Let’s go back to the main method and make sure we pass in these variables when we call this method.

public static void main(String args[]){

    double salary = getSalary();
    int creditScore = getCreditScore();
    scanner.close();

    isUserQualified(creditScore, salary);
}

Now, these variables that are being passed in are NOT the same as these variables in the parameter list for isUserQualified(). These are two different memory locations.

When a method is making a call to another method, what it's passing are arguments, and the method that's receiving it, this is called parameters. The variables have the same name in this case, but I'm going to change this just to show you that they are not the same, so I'm going to just call these c and s, just for short.



This c corresponds to this creditScore — meaning, whatever value is in c is now being stored inside of creditScore. Whatever is inside of s will be stored inside of salary.

Now, let’s at the isUserQualified method. The creditScore in the parameter list is the same variable as the creditScore in the if statement. Same for salary.

public static boolean isUserQualified(int creditScore, double salary){

    if(creditScore >= requiredCreditScore && salary >= requiredSalary){

These are the same because this is now within the same scope. I could not call one of these "sal," for example, because it would then not know what I was talking about. So, this variable, salary, is only recognized within this scope, so it doesn't matter what these are called outside of the method. This argument list maps to this parameter list.

Okay, so we have everything nice and declared.

Now, we can say, "If this is true, go ahead and return true," because remember, this is expecting a boolean. "Else, return false."

public static boolean isUserQualified(int creditScore, double salary){
    if(creditScore >= requiredCreditScore && salary >= requiredSalary){
        return true;
    }
    else{
        return false;
    }
}

Now, your method is only going to execute one return statement. It's going to be the first one that it encounters, and since these are in two different branches, this is legal.

If I were to put another return statement, let's say, "return true," or something here at the end of this method, this will give us an error.

public static boolean isUserQualified(int creditScore, double salary){

    if(creditScore >= requiredCreditScore && salary >= requiredSalary){
        return true;
    }
    else{
        return false;
    }
    return true;
}

Why will this give us an error?

Because I've already taken care of both cases. There's only two possible paths. One of these have to be executed. There's no way that our method would ever even reach here, so this is invalid.

Even though our method is returning this boolean value, we are not required to receive it on the calling end. So having a statement just like this is perfectly fine:

isUserQualified(creditScore, salary);

However, let's make our notifyUser() method

This notifyUser() method is going to print a statement based on if the user is qualified or not. Well, they won't know this unless we give it the boolean value that was returned from here, so it makes sense in this case to read it in, and then pass it to this method.

//Check if the user is qualified
boolean qualified = isUserQualified(creditScore, salary);

//Notify the user
notifyUser(qualified);

We're going to make another method now for the notify — this one won't return anything, and it should take a boolean value.

public static void notifyUser(boolean isQualified){
    if(isQualified){
        System.out.println("Congrats! You've been approved.");
    }
    else{
        System.out.println("Sorry. You've been declined");
    }
}

Okay, so notice in this call from main, I call this variable qualified,

notifyUser(qualified);

But I called it isQualified in the parameter list:

public static void notifyUser(boolean isQualified){

Remember, because of the argument and the parameters being two separate variables.

Now, because I cleaned that up, I will change s and c back to their original names. That way, I've given you two examples where you can have the same name and also different names for arguments and parameters.

Even though we have a variable called salary within the main, we have a totally different variable called salary inside of isUserQualified. And it just so happens that they have the same name and we are passing those values into here.

So, I've given you an example where we're calling a method using the same names.



And I've given you an example where we've called in a method using different variable names.



# InstantCreditCheck.java

package chapter5;

import java.util.Scanner;

/*
 * VARIABLE SCOPE
 * Write an 'instant credit check' program that approves
 * anyone who makes more than $25,000 and has a credit score
 * of 700 or better. Reject all others.
 */
public class InstantCreditCheck {

    static int requiredSalary = 25000;
    static int requiredCreditScore = 700;
    static Scanner scanner = new Scanner(System.in);

    public static void main(String args[]){

        double salary = getSalary();
        int creditScore = getCreditScore();
        scanner.close();

        //Check if the user is qualified
        boolean qualified = isUserQualified(creditScore, salary);

        //Notify the user
        notifyUser(qualified);
    }

    public static double getSalary(){
        System.out.println("Enter your salary:");
        double salary = scanner.nextDouble();
        return salary;
    }

    public static int getCreditScore(){
        System.out.println("Enter your credit score:");
        int creditScore = scanner.nextInt();
        return creditScore;
    }

    public static boolean isUserQualified(int creditScore, double salary){
        if(creditScore >= requiredCreditScore && salary >= requiredSalary){
            return true;
        }
        else{
            return false;
        }
    }

    public static void notifyUser(boolean isQualified){
        if(isQualified){
            System.out.println("Congrats! You've been approved.");
        }
        else{
            System.out.println("Sorry. You've been declined");
        }
    }
}

Now, let's just go ahead and put the debugger on so that we can see how things are happening.

Now, everything that was defined at the class level will have already been initialized, so we see these 3 things are initialized by time we get to the main. Now, this is going to make a call to getSalary().

Using Debugger to Go Inside a Method

With the debugger, if we want to go inside of the method that's going to be called, we need to use this Step Into on the debugger as opposed to the Step Over.

Step Into will go inside of getSalary().

It's going to ask us for our salary, so we click here, and that's going to be on the console. So let's say $35,000, and let's click this.

Now, we notice that $35,000 has been updated, and now we're going to return this back to themain method. So, we returned it to whoever called us, and now it's going to assign that into the salary variable.

Notice now salary has been updated.

Now, we want to get the credit score, so let's Step Into there.

It's going to ask us for our credit score. Let's say we have 800, and we say go ahead to the next line.

Notice now creditScore has been updated to 800. We're going to return that 800 value back to the main method.

So now we’re in main so now we see CreditScore is updated, and we're going to close that scanner.

Now, notice this line.



We want to call isUserQualified. There are 3 variables here in play — qualified, creditScore, and salary. The only ones that we know values for are creditScore and salary because we have called this method and got the return value back.

So, let's go inside of there and we see that we have the information that was passed into here.

It's the same values, and we'll run this, and that says, return true; and that will take us back to the main method.

Now notice, qualified has been updated.

Now, we're going to notify the user, passing in true. Let's go inside

isQualified — this will be true, so we're going to print this, "Congrats! You've been approved."

We're at the end of that, so we go back to the main method.

Even though all things were called, it comes back to the main method. The main method again is what controls this whole flow, and so the program will end once it reaches the main method.

So, I'm just going to resume, and we are done.

# Terminology

Just to give you some terminology with this.

Variables that are defined within a method are called local variables.

So salary is a local variable, and it's local to this main method. Same as creditScore. Same as qualified. This salary is declared withingetSalary(), so this is a local variable.

Variables that are not defined within a local scope are called global variables.

So, these three variables are global to this entire class — requiredSalary, requiredCreditScore, and scanner.

We saw how we can scope a local variable to a method. We could also scope it to any block of code.

For example, inside of this if statement, we could create a brand new variable, and it will be scoped to this_ if statement_. Just to clarify, a variable is scoped to the immediate braces that it appears within.



Optional Independent Exercise

I have an individual exercise for you. You're going to calculate a cellphone bill.



So, what you're going to do is allow the user to input the plan fee and the number of overage minutes. And then you're going to charge 25 cents for every minute that they've gone over, and then a 15% tax on the subtotal.

I want you to create separate methods to calculate the tax, to calculate the overage fees, and to calculate and print the final total.

Please print this as an itemized bill. I have an example of the output expected down below.

Good luck.

Example Output:

Enter base cost of the plan:
82.45
Enter overage minutes:
9
Phone Bill Statement
Plan: $82.45
Overage: $2.25
Tax: $12.71
Total: $97.41

Solution

Programming can be done many different ways, but here’s my solution.



Resources





© 2024 Applitools. All rights reserved. Terms and Conditions Privacy Policy GDPR