Anatomy of a Method
Not Started

Let’s talk about what a method looks like syntactically.

access_modifier return_type method_name (data_type parameterName, data_type parameterName2) { // Method body }

access_modifier should be substituted with the keywords public, protected, global or private. Similar to member variables, the default access modifier for methods will be private and implicitly declared. You can explicitly declare a method as private if you wish. private methods can only be called from the class that declared it. public methods can be called from any class in the namespace.

return_type should be substituted with the datatype that will be returned when the method is done running. The datatype can be anything, including a custom class. It can also be nothing. If a method returns no data, the datatype can be marked using the keyword void. Data is returned in the method body using the return keyword. More on that in a second.

method_name should be substituted with the name of a method. The same rules as variable names apply here. Method names can’t start with numbers and can’t contain special characters other than an underscore _. The suggested stylistic naming convention here is camelCase, just like the style convention with variables. Remember, Apex is case-insensitive, so it’s up to developers to drive capitalization consistency.

The ( and ) work the same as they do with constructors. They are used to provide a comma-separated list of variables and their datatypes to the method. If there are no parameters to pass in, it will be indicated with empty open and close parentheses (). The method’s name and parameter list come together to create a method signature.

{ and } indicate the beginning and the end of a method. They define the method’s body and scope. This is where the actual logic is declared. If the method has declared a return_type, the method body must include a return statement. This statement is the keyword return followed by the variable that must be returned when the method is done running. The datatype being returned must match the datatype declared on the return_type If the method was marked as void, it should not have a return statement.

Enough theory. Let’s look at some real code. Recall our Employee class:

public class Employee { String firstName; public Integer startYear {get; private set;} Employee(String firstName, Integer startYear){ this.firstName = firstName; this.startYear = startYear; } }

And the code that was instantiating the objects:

public class EmployeeController { Integer currentYear = 2023; Employee jerryEmployee = new Employee('Jerry', 2015); Integer jerryTenure = currentYear - jerryEmployee.startYear; Employee elaineEmployee = new Employee('Elaine', 2018); Integer elaineTenure = currentYear - elaineEmployee.startYear; }

Instead of this spaghetti code, let’s refactor it.

We’ll move the employeeTenure calculation into a method named calculateTenure that accepts an Employee object as a parameter. In the body, we’ll apply the formula and then return the result as an Integer called tenure. This method will be called each time an employee’s tenure must be calculated:

public class EmployeeController { Integer currentYear = 2023; Employee jerryEmployee = new Employee('Jerry', 2015); Integer jerryTenure = calculateTenure(jerryEmployee); Employee elaineEmployee = new Employee('Elaine', 2018); Integer elaineTenure = calculateTenure(elaineEmployee); private Integer calculateTenure(Employee emp){ Integer tenure = this.currentYear - emp.startYear; return tenure; } }

Great!

The method is called using the calculateTenure(...) syntax. Each instance of the Employee class is passed in as an argument.

The method accepts the Employee object as a parameter and locally uses the variable name emp to keep track of it. emp is a reference to the exact same object that was passed in. So if we passed in jerryEmployee as an argument, we can use the parameter emp to access all the data inside jerryEmployee.

In the method body, each object's member variable is accessed via the dot operator to perform the calculation. The result is stored in tenure. The return keyword passes tenure back to the original caller.

This is great because our code is a bit more DRY now. If the formula ever changes, we’ll just update the calculateTenure method.

This is where scope really starts to matter. Scope determines the accessibility of a variable. The variable tenure has a scope limited to the method body where it was declared. It cannot be accessed outside of that method, which is why we depend on the method's return type to convey the information.

The scope of currentYear belongs to the entire class. So, everything within the class can access this variable. This means we can’t declare a variable named currentYear in the calculateTenure method. The class’s scope encapsulates the method’s scope.

Up to this point, we haven't been working with classes and methods, so we didn't need to concern ourselves with scope. However, moving forward, it will become an important consideration.

Challenge

We'll use this as an opportunity to refactor the totalContractValue calculation from the "Operator Precedence" lesson in the Variables course.

A contract's total value is determined using this formula: nonRecurringRevenue + (contractLengthInMonths * monthlyRecurringRevenue).

Create a zero parameter method named calculateTotalValue which uses the 3 Integer member variables already defined. Use the member variables to create the formula above. Return the results of the calculation as an Integer.