Method Parameters¶
Consider two verses in the “Old MacDonald” song:
Verse 1 |
Verse 2 |
---|---|
Old MacDonald had a farm |
Old MacDonald had a farm |
E-I-E-I-O |
E-I-E-I-O |
And on that farm he had a cow |
And on that farm he had a duck |
E-I-E-I-O |
E-I-E-I-O |
With a moo-moo here |
With a quack-quack here |
And a moo-moo there |
And a quack-quack there |
Here a moo, there a moo |
Here a quack, there a quack |
Everywhere a moo-moo |
Everywhere a quack-quack |
Old MacDonald had a farm |
Old MacDonald had a farm |
E-I-E-I-O |
E-I-E-I-O |
Each verse is identical, except for the animal (cow vs duck) and the noise (moo vs quack). We can create a method named verse to abstract the repetitive lines, but the method will need two formal parameters, which are placeholders that allow different values to be substituted for the animal and noise when the method is called. The method body will use the formal parameter variables to customize the print statements.
public static void verse( String animal, String noise ) {
System.out.println( "Old MacDonald had a farm" );
System.out.println( "E-I-E-I-O" );
System.out.println( "And on that farm he had a " + animal );
System.out.println( "E-I-E-I-O" );
System.out.println( "With a " + noise + "-" + noise + " here") ;
System.out.println( "And a " + noise + "-" + noise + " there" );
System.out.println( "Here a " + noise + ", there a " + noise );
System.out.println( "Everywhere a " + noise + "-" + noise );
System.out.println( "Old MacDonald had a farm" );
System.out.println( "E-I-E-I-O" );
}
When you call the method, you provide values between the parentheses, called actual arguments or actual parameters, that are copied into the formal parameter variables.
verse( "cow", "moo" );
verse( "duck", "quack" );
The main method will call the verse method twice, once for the cow and once for the duck.
The call stack diagram shown below corresponding to the verse( "cow" , "moo" );
method call.
If you look at the frame on the call stack for the verse
method, it
contains not only the current line but also the formal parameter variables and values. The print statements will use the formal parameter variables to customize the output.
Update the main method of the E01Song
program to add a third verse to the song with another animal and noise. Use the debugger to step through the code.
Refactoring - Removing Duplicate Code¶
Sometimes a program has blocks of code that are similar, but not exactly the same. The code might perform a similar function but with different values.
We can introduce a method to perform a task that can be generalised by having formal parameter variables. The method can adapt to a variety of situations depending on the values passed into the method.
The E02PayrollCalculator
class listed below calculates and prints the weekly pay for two employees.
Do you notice any redundancy?
public class PayrollCalculator { public static void main(String[] args) { double hourlyRate, hoursWorked, weeklyPay; String employee; //Calculate weekly pay for Fred employee = "Fred"; hourlyRate = 12.50; hoursWorked = 20; weeklyPay = hourlyRate * hoursWorked; System.out.println(employee + ":" + weeklyPay); //Calculate weekly pay for Amir employee = "Amir"; hourlyRate = 15.0; hoursWorked = 35; weeklyPay = hourlyRate * hoursWorked; System.out.println(employee + ":" + weeklyPay); } }
The table below displays the code for each employee side by side. The first three lines of code are the same except for the value in the right hand side of each assignment, while the last two lines of code are identical.
Calculate pay for first employee |
Calculate pay for second employee |
---|---|
employee = “Fred”; |
employee = “Amir”; |
hourlyRate = 12.50; |
hourlyRate = 15.0; |
hoursWorked = 20; |
hoursWorked = 35; |
weeklyPay = hourlyRate * hoursWorked; |
weeklyPay = hourlyRate * hoursWorked; |
System.out.println(employee + “:” + weeklyPay); |
System.out.println(employee + “:” + weeklyPay); |
The redundant calculation and printing can be eliminated by adding a new method named calculatePay
.
Three formal parameters are needed to allow different
values to be passed into the method: employee
, hourlyRate
, and hoursWorked
.
The weeklyPay
variable is declared in the method body, since its value is computed using the formal parameter variables.
A variable declared in a method is called a local variable.
public static void calculatePay ( String employee, double hourlyRate, double hoursWorked) {
double weeklyPay = hourlyRate * hoursWorked;
System.out.println(employee + ":" + weeklyPay);
}
When the calculatePay method is called, actual values must be provided for each parameter:
calculatePay ( "Fred", 12.50, 20.0 );
calculatePay ( "Amir", 15.00, 35.0 );
Update the PayrollCalculator
program to add the calculatePay
method. Update the main
method to
call the calculatePay
method twice to compute the pay for each employee.
Use the debugger to confirm that your main method makes the two calls to calculatePay, with the correct values passed into the method.
- Chen 20.00 15.00
- Incorrect. The weeklyPay is computed as 20.00 * 15.00. This result is used in the print statement.
- Chen:300.0
- Correct.
- employee:weeklyPay
- Incorrect. The actual values of the employee and weeklyPay variables will be printed.
5-2-1: What is printed by the method call: calculatePay ( “Chen”, 20.00, 15.00 ) ;
Note
A call stack method frame stores formal parameter variables as well as local variables.
- Chris:125.0
- Correct.
- employee:weeklyPay
- Incorrect. The actual values of the employee and weeklyPay variables will be printed.
- "Chris":125.0
- Incorrect. The CodeLens tool just shows quotes to let you know the value is a String.
5-2-2: The figure shows the call stack after line 8 executed. Notice the weeklyPay local variable is stored in the calculatePay method frame on the call stack. What is printed when line 9 executes?
When a method is called, the right method definition is found by checking the method header at the top of the method definition to match the name, number and type of arguments, and return type.
- mystery("9");
- The type of the actual argument "9" is String, but the formal parameter i is an int.
- mystery(9);
- The type of the actual argument 9 and the formal parameter i are both int.
- mystery(5, 7);
- The method expects one int to be passed as an actual argument, not 2.
5-2-3: Based on the method header shown below, which method call is correct?
public static void mystery(int i)
- mystery("abc", 9);
- The actual argument and formal parameter types match.
- mystery("xyz", "9");
- The second parameter i has type int, while the second argument "9" is a string.
- mystery(9, 5);
- The method expects a string and an int as actual arguments, not two ints.
5-2-4: Based on the method header shown below, which method call is correct?
public static void mystery(String s, int i)
- mystery("true", "hello");
- "true" is a String, not a boolean.
- mystery("hello", false);
- The first argument should be a boolean, and the second argument should be a String.
- mystery(true, "hello");
- The actual argument and formal parameter types match.
5-2-5: Based on the method header shown below, which method call is correct?
public static void mystery(boolean b, String s)
- mystery("5");
- Incorrect. This will call the first method, which expects a String value.
- mystery(5);
- Correct. The second method expects an integer value.
- mystery(5, "5");
- Incorrect. This will call the third method, which expects two values to be passed as arguments.
5-2-6: A class can have several methods with the same name as long as the type or number of formal parameters is different.
You may recall from the constructor lesson that this is called “overloading”.
Select the method call that causes the program to print second method 5
.
public class TestArgumentPassing {
public static void mystery ( String str ) {
System.out.println("first method " + str);
}
public static void mystery ( int num ) {
System.out.println("second method " + num);
}
public static void mystery ( int num , String str) {
System.out.println("third method " + num + "," + str);
}
public static void main (String[] args) {
}
}
Variable Scope¶
A variable may be available for use in some lines of code, but not others. The scope of a variable is the region of the program that is it visible, which means it is accessible by name and can be used in the code.
A variable declared inside a method is called a local variable. The scope of a local variable is the method body in which it is declared. You can’t use a variable before it is declared, so in fact the scope begins on the line that declares the variable and continues until the last line of code in the method or block. The local variable’s memory location is only available while the method is executing. When the method completes, the memory location is released. If you called the method again, the old value is not available.
Use the debugger button to step through the two method calls in the E03ScopeExample
program. Notice the inches
and centimeters
variables are
visible in the inchesToCentimeters
method but not the main
method.
The inchestToCentimeters
method defines a local
variable centimeters
, which is only visible inside that method.
The main method can’t see or use the variable. Each time the inchestToCentimeters method is called, a new memory location is
created for the local variable.
A formal parameter is like a local variable in that its scope is the body of the corresponding method.
The inches
variable is only visible in the inchesToCentimeters
method body.
Note
A local variable has its value initialized within the method body.
A formal parameter has its value initialized by the method call.
You must explicitly assign a local variable a value before you can use it in a calculation. The compiler will warn you if you try to use a local variable in a calculation or print statement before it has been assigned a value.
- print1
- Method print1 accesses num, which is a formal parameter with method level scope.
- main
- Method main can accesses the local variable age, since it is declared in the main method.
- print1 and main
- Variable age is declared in the main method, so it can't be accessed in the print1 method.
5-2-8: The variable age
is visible in which method(s)?
public class Visibility {
public static void print1(int num) {
System.out.println("num is " + num);
}
public static void main(String[] args) {
int age = 20;
print1(age);
}
}
- print1
- Method print1 accesses num, which is a formal parameter with method level scope.
- print2
- Method print2 accesses age, which is not accessible since it is declared in the main method.
- main
- Method main accesses age, which is a local variable with method level scope..
5-2-9: Which method has a scope error (i.e. uses a variable that is not visible in that method)?
public class Visibility {
public static void print1(int num) {
System.out.println("num is " + num);
}
public static void print2() {
System.out.println("age is " + age);
}
public static void main(String[] args) {
int age = 20;
print1(age);
print2();
}
}
Method Tracing¶
A method can call other methods to help it do its job.
inches –> centimeters
-
The values of the variables inches and centimeters should be printed out, not the words.
10 –> 25
-
Two doubles should be printed, not two ints, and the centimeters should be 25.4
25.4 –> 10
-
Inches should be printed before centimeters.
10 –> 12.54
-
c = 10 * 2.54 = 25.4, not 12.54.
10.0 –> 25.4
-
Correct! centimeters = 10 * 2.54 = 25.4.
5-2-10: Consider the following methods:
public static void inchesToCentimeters(double i) {
double c = i * 2.54;
printInCentimeters(i, c);
}
public static void printInCentimeters(double inches, double centimeters) {
System.out.println(inches + "-->" + centimeters);
}
public static void main(String[] args) {
inchesToCentimeters(10);
}
What is printed when the main method is run? It might help to draw out a stack diagram on paper, or use the CodeLens visualizer to step through the code.
printSlices(slicesPerPerson);
-
Correct! If you had 4 people, slicesPerPerson would be 8/4=2 and printSlices would print out “Each person gets 2 slices each”.
printSlices(numOfPeople);
-
If you had 4 people, this would print out that they get 4 slices each of an 8 slice pizza.
printSlices(8);
-
This would always print out 8 slices each.
splitPizza(8);
-
This would not call the printSlices method.
splitPizza(slicesPerPerson);
-
This would not call the printSlices method.
5-2-11: Consider the following methods.
public static void splitPizza(int numOfPeople) {
int slicesPerPerson = 8/numOfPeople;
/* INSERT CODE HERE */
}
public static void printSlices(int slices) {
System.out.println("Each person gets " + slices + " slices each");
}
Which of the following lines would go into /* INSERT CODE HERE */
in the method splitPizza in
order to call the printSlices
method to print the number of slices per person correctly?
- 25 and 2
- Correct.
- 25 and .5
- The order of the arguments to the divide(x,y) method will divide x by y and return an int result.
- 2 25
- The square(x) method is called before the divide(x,y) method.
- 25 2
- The main method prints out " and " in between the method calls.
- Nothing, it does not compile.
- Try the code in the CodeLens visualizer.
5-2-12: What does the following code print?
public class MethodTrace {
public static void square(int x) {
System.out.print(x*x);
}
public static void divide(int x, int y) {
System.out.println(x/y);
}
public static void main(String[] args) {
square(5);
System.out.print(" and ");
divide(4,2);
}
}
Pass by value¶
Java uses pass by Value when it passes arguments into a method. This means that a copy of the actual parameter value is stored in the formal parameter variable. The original value outside the method is not changed if a new value is assigned to the formal parameter within the method body. It is generally not a good idea to change the value of a formal parameter inside a method, however it is possible as the example below shows.
Open the CallByValue
program. Use the debugger to watch how the square method
alters the value of x, while the value of y in the main method is not affected.
Try changing the name of the variable in the main method to “x” and rerun the program. You should see that the variable in the main method remains unaffected by changes made in the square method, even when the variables have the same name.
If you pass in an argument that holds a reference to an object, like a String or Person or Turtle object, a copy of this reference is passed in and saved in the parameter variable. You will explore this more in the following unit.
Programming Challenge : Calculating Shipping Costs¶
The E05ShippingCostCalculator class computes and prints the shipping cost for 3 different items based on their weight. The cost is 9.95 if the item weighs less than 15.0, otherwise the cost is 12.95. While the if-else statements are not identical due to the different variables names (weight1 vs weight2 vs weight3, cost1 vs cost2 vs cost3), each tests the weight and assigns the cost in the same way.
The redundant code will be eliminated by adding a new method to compute and print the cost based on item weight.
Update the
E05ShippingCostCalculator
program to add a new methodcalculateShipping
that has one formal parameter forweight
. The method will need a local variable forcost
. The method should test the weight and print the corresponding cost.Update the main method to replace the existing code with 3 calls to
calculateShipping
, each passing an actual value for weight. The main method will no longer need local variables.Confirm that the new version of the program produces the same output as the original version.
Summary¶
When you call a method, you can give or pass in values called arguments or actual parameters inside the parentheses. The arguments are saved in local formal parameter variables that are declared in the method header.
Values provided in the arguments in a method call need to correspond to the order and type of the parameters in the method signature.
When an actual parameter is a primitive value, the formal parameter is initialized with a copy of that value.
New values assigned to the formal parameter within the method have no effect on the corresponding actual parameter.