Methods 1 - Introduction to methods
- Basic purpose of methods.
- Term: call = Execution proceeds to the code in a method.
- Term: return = Execution of a method finishes and then continues after point of call, possibly using a value form the method.
- Term: static method = Method requiring no extra object.
- Term: instance method = Method that operates on the object before the dot.
- Static call syntax: className . methodName ( arguments )
Basic idea - A named group of statements - Verbs
By now you have used a lot of the predefined library methods, and written many main methods. This chapter explains methods in more detail.
Java statements are grouped together in methods. Each method must be inside a class. Every method has a name, which starts with a lowercase character and typically is a verb because it does something.
Other terms: The idea of method is in every programming language, but different terms are used in many languages. You might have seen terms like function, procedure, or subroutine. We'll use method consistently here, but you will hear programmers using these equivalent terms occasionally.
Business analogy - services provided by an organization
You could think of classes as corresponding to departments in an organization, and methods as being the services they provide. Let's take an example of calling the telephone information service to get someone's phone number. When you make the call, you pass information, the name of the person whose number you want, to the method (information service). This called "method" then does something, and returns a value to you (the desired phone number). Just as you don't have to know how the information service performs its job, you typically don't need to know exactly how a method does its work, unless of course, you are writing it.
Hierarchical organization.
Computer programs are structured in many ways like an organization --
higher levels rely on others to do much of the work.
They "call" on lower levels to do the work, passing them all necessary "arguments".
In a similar way, the top level of a computer program, main
, often consists largely of method calls,
and those methods may in turn call on yet other methods.
Terms: call and return
Call. When a method call is encountered in a program, the program remembers where it was and execution goes to the method (calls the method). After a small amount of initialization, the statements in the method are executed starting at the beginning.
Return.
When the end of the method is reached or
a return
statement is executed, the method returns to the where it was
called from, and execution continues in the calling method from that point.
A method may return a value (eg, parseDouble
) or not (showMessageDialog
).
The call-return terminology is almost universal.
Static (class) methods
Static. This starts with static (also called class) methods because all applications start with the static method main, and many of the early library methods that you use are static methods. Static methods are different than instance methods because they don't have an extra object passed to them.
Instance methods are associated with an object (an "instance" of a class).
Identifying methods
Parentheses follow name. You can identify a method name because it is always followed by left and right parentheses, which may enclose arguments (parameters). If you see a left parenthesis with a name preceding it, it will be a method call or definition, or a constructor (constructors are very similar to methods). In the following example each method name is highlighted.
When calling methods outside of the current class, eg, in the Java library, static methods are preceded by the class name (followed by a dot), and instance methods are preceded by an object. When a static method is defined, the keyword "static" will preceded it. The example below has only static methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// File : methods/KmToMiles.java // Purpose: Convert kilometers to miles. Use JOptionPane for input / output. // Author : Fred Swartz // Date : 22 Apr 2006 import javax.swing.*; public class KmToMiles { //============================================================ constants private static final double MILES_PER_KILOMETER = 0.621; //================================================================= main public static void main(String[] args) { //Note 1 //... Local variables String kmStr; // String km before conversion to double. double km; // Number of kilometers. double mi; // Number of miles. //... Input kmStr = JOptionPane.showInputDialog(null, "Enter kilometers."); km = Double.parseDouble(kmStr); //... Computation mi = km * MILES_PER_KILOMETER; //... Output JOptionPane.showMessageDialog(null, km + " kilometers is " + mi + " miles."); } } |
Notes
- This defines a method called "main". Everything between the "{" on the end of this line to the matching "}" second from the end is the "body" of the method.
The above code defines the static main
method, which someone
(eg, the operating system) will call with KmToMiles.main(. . .)
.
To do its work, main
calls on other methods:
showInputDialog
, which is defined in the JOptionPane
class,
parseDouble
, which is defined in the Double
class, and
showMessageDialog
, which is also in the JOptionPane
class.
Whenever you call a static method in a different class, precede it with the name of the class containing its definition, followed by a dot. If you don't specify the class name, it assumes the method is defined in the current class.
Identifying instance methods
Object precedes. Instance method calls are identified in the following program. Note that they are all preceded by an object reference. This object is used by the methods to do their work. In this case, the objects are strings.
In addition to supplying the object's data to the method, the class of the object, eg String, is where the method is defined.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// File : dialog/capitalize/Capitalize2.java // Purpose: Capitalize first letter of each name. Declare with first use. // Author : Fred Swartz - placed in public domain. // Date : 30 Mar 2006 import javax.swing.*; public class Capitalize2 { public static void main(String[] args) { //.. Input a word String inputWord = JOptionPane.showInputDialog(null, "Enter a word"); //.. Process - Separate word into parts, change case, put together. String firstLetter = inputWord.substring(0,1); // Get first letter String remainder = inputWord.substring(1); // Get remainder of word. String capitalized = firstLetter.toUpperCase() + remainder.toLowerCase(); //.. Output the result. JOptionPane.showMessageDialog(null, capitalized); } } |
Methods 2 - Actual arguments (parameters)
- Left-to-right argument evaluation
- Term: actual argument = value which is passed in a method call.
- Term: void method = method that doesn't return a value.
- Term: value-returning method = method that does return a value.
Terms: actual argument, argument, actual parameter, parameter
The values that are passed to a method are called actual arguments in the Java specification. However, it is very common for them to be called just arguments, actual parameters, or just plain parameters. These terms are so used interchangeably so often that even the Java specification isn't entirely consistent. For a value which is passed in a call I'll try to stick to actual argument or just argument, which are generally regarded as the "best" terms.
Identifying method arguments
When you call a method, you can pass information for it to use. These actual arguments are inside parentheses following the method name. Use commas to separate arguments if there is more than one. The previous program is shown below, but this time the arguments in the calls are highlighted.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// File : methods/KmToMilesArgs.java // Purpose: Convert kilometers to miles. Use JOptionPane for input / output. // Author : Fred Swartz // Date : 22 Apr 2006 import javax.swing.*; public class KmToMilesArgs { //============================================================ constants private static final double MILES_PER_KILOMETER = 0.621; //================================================================= main public static void main(String[] args) { //... Local variables String kmStr; // String km before conversion to double. double km; // Number of kilometers. double mi; // Number of miles. //... Input kmStr = JOptionPane.showInputDialog(null, "Enter kilometers."); km = Double.parseDouble(kmStr); //... Computation mi = km * MILES_PER_KILOMETER; //... Output JOptionPane.showMessageDialog(null, km + " kilometers is " + mi + " miles."); } } |
Argument evaluation
Before a method is called, the arguments are evaluated left-to-right.
In the example above most arguments are simple values, except the
second argument in the call to showMessageDialog
.
Before the call can be made, this argument expression must be evaluated
by performing the conversions to string and the concatenations.
Void and value-returning methods
A method may return a value. In the example above,
showInputDialog
returns a String
and parseDouble
returns a double value.
These method calls can be used anywhere in an expression
where a String or double value is required. Here they simply
provide the value for the right side of an assignment.
void
.
If a method has a "side effect", but doesn't produce a value,
it is called a void method.
The showMessageDialog
method shows something to the
user, but doesn't return a value, and is a void method.
When a method is defined, you need to specify the keyword void
if it doesn't return a value. You can see this on line 13 where the
main
method definition starts.
Methods 3 - Defining a static method
- Show how to define a method.
- Explain parts of method header.
- Term: formal parameter = variable in method which gets the argument value.
- Syntax of method header
Method header syntax
A method header is the part of the method definition that occurs at the beginning. The following definition leaves out a few obscure features, but gives the syntax of ordinary method headers.
See Syntax Notation to understand how to read the following.
methodHeader | = | [visibility] ["static "] returnType methodName "(" [parameterList] ")" . |
visibility | = | "public " | "private " | "protected " . |
parameterList | = | parameterDeclaration {"," parameterList} . |
parameterDeclaration | = | type ParameterName . |
returnType | = | "void" | type |
How to define your own method
The previous program is rewritten below to define a method to convert from kilometers to miles.
The method call, and the first line (header) of the method definition are highlighted.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// File : methods/KmToMilesMethod.java // Purpose: Convert kilometers to miles using a method. JOptionPane IO. // Highlight call and method definition header. // Author : Fred Swartz // Date : 22 Apr 2006 import javax.swing.*; public class KmToMilesMethod { //============================================================ constants private static final double MILES_PER_KILOMETER = 0.621; //================================================================= main public static void main(String[] args) { //... Local variables String kmStr; // String km before conversion to double. double km; // Number of kilometers. double mi; // Number of miles. //... Input kmStr = JOptionPane.showInputDialog(null, "Enter kilometers."); km = Double.parseDouble(kmStr); //... Computation mi = convertKmToMi(km); //Note 1 //... Output JOptionPane.showMessageDialog(null, km + " kilometers is " + mi + " miles."); } //========================================================= convertKmToMi private static double convertKmToMi(double kilometers) { //Note 2 double miles = kilometers * MILES_PER_KILOMETER; return miles; } } |
Notes
- Call our own method below to do the conversion. We could have qualified the name with our class name, KmToMilesMethod.convertKmToMi(km), but this is unnecessary when calling a static method in the same class.
- Altho this method is trivial, just a multiplication, it is good practice to separate the "model", or "logic", from the user interface. As programs become larger, this separation becomes essential.
Anatomy of the convertKmToMi
method header
We'll take a look at each of the parts of the method header in order.
- Visibility -
public
,private
, or package -
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
For greatest reliability and flexibility in your programs, you should always give methods the lowest visibility to others that you can.
When you define a method, you should think about who can use it. Generally you want to choose the lowest level of visibility that makes your program usable, either
private
or the default (package). Here are the four options, from least visible to most visible.private
- If you don't want any other class to use it, declare it private. This is a good choice.- None (package) - If you don't specify anything, the default visibility allows
only classes in the same package (directory) to
see it. This is a common choice. It's common to use
public
visibility when package visibility is more appropriate -- I do it myself. The lack of a keyword for package visibility makes it a little harder to read. protected
- Don't use thisprotected
, except in certain cases to let a child class see it. Even then, its use is controversial.public
- Let's anyone see it. Choose this if you've defined a method that will be used by others outside of your project. Note thatmain
must be declaredpublic
so the run-time system can call it.
- Class (static) or instance method
-
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
A method should be declared
static
if it doesn't user instance variables or methods. A static method must use only only parameters, local variables, and static constants, and other static methods in the same class. If thestatic
keyword is omitted, the method will be an instance method. This example uses static, but soon you will learn about instance methods too. - Return type
-
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
- Method name
-
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
Method names should begin with a lowercase letter. Method names are typically verbs, whereas variable names are usually nouns.
- Parameter(s)
-
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
Parameters are enclosed in parentheses following the method name. They are also called formal parameters). There is only one parameter in this example -
kilometers
, but if there are more, they must be separated by commas. The type of each parameter is specified before the name (eg,double
). Parameters are local variables that only exist inside the method. They are assigned initial values from the arguments when the method is called. - Method body
-
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
The body of a method is the statements which are executed when the method is called are enclosed in braces following the the method header. Additional local variables may be defined (eg,
miles
). - Return statement
-
private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
A method returns to the caller after it has done what it wants. If the method returns a value (not a void method), it must contain a
return
statement that specifies a value to return. When execution reaches thereturn
statement, control transfers back to the calling method, passing a return value to it. - Returning an expression
-
The above example returns the value in the local variable miles. The return statement can be followed by any expression of the appropriate type, not just a single value. For example, this method body could have been written as a single return statement.
private static double convertKmToMi(double kilometers) { return kilometers * MILES_PER_KILOMETER; }
Order of method definitions doesn't matter
If you define multiple methods in a class, you don't have to worry about the order of the definitions, unlike some other languages.
Methods 4 - Local variables
- Local variables are declared within a method.
- Local variable lifetime is from method entry to method return.
- Local variable visibility is only within the method.
- Local variables have no initial value.
- Parameter variables are local variables initialized from the argument values.
final
modifier to prevent assignment to parameters.
- Don't assign to parameter variables.
Local variables
Now that we've written two methods, main
and convertKmToMi
,
you should know a little more about the variables in them.
Variables that are declared in a method are called local variables.
They are called local because they can only be referenced and used
locally in the method in which they are declared.
In the method below miles
is a local variable.
private static double convertKmToMi(double kilometers) {
double miles = kilometers * MILES_PER_KILOMETER;
return miles;
}
Visibility: Only in defining method
No code outside a method can see the local variables inside another method. There is no need, or even possibility, of declaring a local variable with a visibility modifier -- local variables are automatically known only in the method itself.
Lifetime: From method call to method return
Local variables are created on the call stack when the method is entered, and destroyed when the method is exited. You can't save values in local variables between calls. For that you have to use instance variables, which you'll learn about a little later.
Initial value: None
Local variables don't have initial values by default -- you can't try to use their value until you assign a value. It's therefore common to assignment a value to them when they're declared.
Compiler error. If you try to use a local variable before it's been assigned a value, the compiler will notice it and give an error message. But the compiler doesn't really know the exact order of execution in a program, so it makes some conservative assumptions. These assumptions can sometimes be too conservative, and there are cases where you must initialize a local variable even though you know it will have a value before it's referenced.
// BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD private static double convertKmToMi(double kilometers) { double miles; return miles; // Won't compile because nothing was assigned to miles. }
Parameters are preinitialized local variables
Method parameters are basically implemented as local variables. They have the same visibility (none outside the method) and lifetime (created on method call, destroyed on method return).
Preinitialized. The difference is that parameters are initialized from the corresponding argument values.
// Both kilometers and miles are implemented as local variables. private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; }
Style: Don't assign to a parameter
You can assign to a parameter variable, just as you would to a local variable, but this is often considered bad style because it can deceive the casual reader in two ways:
- Unexpected meaning change.. Programmers assume parameter variables represent actual argument values. Assigning to parameters breaks that assumption.
- Doesn't change actual argument.
Because formal parameter variables are really local variables,
assigning new values to them doesn't have any effect on the
actual parameters.
However, in some programming languages assignment to a parameter can assign to the corresponding actual parameter (eg, C++ reference parameters). Therefore if you write an assignment to a formal parameter variable, it may mislead the careless programmer with a C++ background. Or the reader may pause and try to decide if you thought you were assigning to the actual argument. In either case it reduces the readability.
Example. The example below shows how a parameter could be reused. The overhead of declaring an extra variable is just about zero, so this really isn't more efficient, and even this small example is astoundingly misleading.
// BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD private static double convertKmToMi(double kilometers) { kilometers = MILES_PER_KILOMETER * kilometers; // BAD - Don't do this, altho it works. return kilometers; }
Style: final
keyword prevents assignment
Some programmers recommend using the final
keyword for each parameter. This prevents assignment to
the parameter. Few programmers do this because
it adds extra clutter, which in a different way reduces
the readability.
The use of self-restraint in
assigning to parameters is usually suffcient, but specifying final
isn't
a bad idea.
private static double convertKmToMi(final double kilometers) {
double miles = kilometers * MILES_PER_KILOMETER;
return miles;
}
Methods 5 - Example with three methods
- Show definition of multiple methods.
- All code is in methods.
- Style: The main method often consists largely of method calls.
- Style: Methods should generally be no larger than one page.
Here is another variation of the program, this time using three methods. Altho there is no real need for these methods in such a small program, large programs are in fact composed of many small methods. It is the essential way that all code is structured.
Each of the user-defined method names, both in the call and the definition, is hilited.
- One method is void, which means it doesn't return a value.
- Three methods call other methods.
- The main program consists mostly of calls to other methods.
Source code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// File : methods/KmToMilesMethods.java // Purpose: Converts kilometers to miles using two methods. // Author : Fred Swartz - placed in public domain // Date : 22 Apr 2006 import javax.swing.*; public class KmToMilesMethods { //========================================================= constants private static final double MILES_PER_KILOMETER = 0.621; //============================================================== main public static void main(String[] args) { double kms = getDouble("Enter number of kilometers."); double miles = convertKmToMi(kms); displayString(kms + " kilometers is " + miles + " miles."); } //===================================================== convertKmToMi // Conversion method - kilometers to miles. private static double convertKmToMi(double kilometers) { double miles = kilometers * MILES_PER_KILOMETER; return miles; } //========================================================= getDouble // I/O convenience method to read a double value. private static double getDouble(String prompt) { String tempStr; tempStr = JOptionPane.showInputDialog(null, prompt); return Double.parseDouble(tempStr); } //===================================================== displayString // I/O convenience method to display a string in dialog box. private static void displayString(String output) { JOptionPane.showMessageDialog(null, output); } } |
Methods 6 - How call works
- Examine the method call/return process in more detail.
- Term: call stack = Memory that is used to save return address and local variables.
- Term: stack frame = The storage on the call stack that is used by one method.
- None.
The table below shows how the call stack changes as calls and returns in the KmToMilesMethods program are made. This shows the first 8 changes to the call stack after main is entered.
Dynamic changes in the call stack memory allocation
The table below shows how the call stack changes as calls and returns in the KmToMilesMethods program are made. This shows the first 8 changes to the call stack after main is entered.
There is actually something before main on the call stack, and the library methods that are called call many methods of their own, which isn't shown here because we don't need to know what they call.
Stack frame. Each box represents the information that's stored on the call stack for each method. This block of information is often called a stack frame. There is internal information associated with the method, for example, it saves the place to resume execution in the calling method. Each stack frame is labelled with the method name and a list of parameters and local variables that are allocated on the stack. "???" is written when we don't know (or care) what the local variables are that are used by a library method.
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
Typical call sequence
- Evaluate arguments left-to-right. If an argument is a simple variable or a literal value, there is no need to evaluate it. When an expression is used, the expression must be evaluated before the call can be made.
- Push a new stack frame on the call stack.
When a method is called, memory is required to store the following information.
- Parameter and local variable storage. The storage that is needed for each of the parameters and local variables is reserved in the stack frame.
- Where to continue execution when the called method returns. You don't have to worry about this; it's automatically saved for you.
- Other working storage needed by the method may be required. You don't have to do anything about this because it's handled automatically.
- Initialize the parameters. When the arguments are evaluated, they are assigned to the local parameters in the called method.
- Execute the method. After the stack frame for this method has been initialized, execution starts with the first statement and continues as normal. Execution may call on other methods, which will push and pop their own stack frames on the call stack.
- Return from the method. When a return statement is encountered, or the end of a void method is reached, the method returns. For non-void methods, the return value is passed back to the calling method. The stack frame storage for the called method is popped off the call stack. Popping something off the stack is really efficient - a pointer is simply moved to previous stack frame. This means that the current stack frame can be reused by other methods. Execution is continued in the called method immediately after where the call took place.
Review Questions
The table above shows only the first part of the execution. Show how the call stack would change during the remainder of the execution of the program.