3. 0011 - Methods
What’s the Point?
-
Define and call methods
-
Understand variable scope
-
Pass data to methods
-
Return values from methods
-
Overload a method
Source code examples from this chapter and associated videos are available on GitHub.
As our programs begin to get larger and more complex, it will be important to keep our code organized. Each program we write is contained within a class, and classes are the basic building block of an OOP program; we’ll explore them in more detail in the next chapter. Within a class or program, we can organize code in methods. A method is a collection of statements that work together to complete a single task. Consider the assembly instructions for building a LEGO set.

It might take dozens of small steps to complete the set, but taken together, the instructions execute a single task: building the set. A method is conceptually the same.
If you’ve worked with other programming languages, you may know methods by a different name. In Python, we use functions, and in other languages we use procedures or subroutines. All of those terms pretty much mean the same thing, but in Java they’re called methods. And really, they’re generally called methods whenever we’re using object-oriented programming, so even in Python we sometimes call them methods.
There are a variety of reasons to break our code into methods, but an important advantage for now is reusability. Once we create a method, we can use it as often as we’d like. That means we don’t have to type the same code over and over. In turn, that improves our code’s maintainability. If we have to perform some calculation ten times in our program and have written out that calculation all ten times, a change to the calculation means updating it in all ten places. But if we put that calculation in a method and use that method ten times, we can just update the method and our changes will automatically be used all ten times. We’ll see additional advantages to methods as we learn more about programming.
Once we define a method, we invoke the method each time we want it to execute. We also say that we call a method, which sounds a little cooler than invoke but means the same thing.
3.1. Defining Our Own Methods
We’ve been defining a method from the start.
Each program we write includes a method called main
, which the Java runtime invokes when we run the program.
We’ve also been calling (invoking) methods from the start.
To output text, we’ve been calling the println()
and print()
methods.
In Java, parentheses always indicate a method, whether or not there is anything inside of the parentheses. Anytime you see parentheses in Java code, you’re looking at either a method definition or a method call. |
A method definition includes a method header followed by a code block.
1
2
3
public static void displayCopyright() {
System.out.println("(C) 2025 by Tim McMichael. All rights reserved.");
}
-
The
public
keyword is an access modifier. Defining the method aspublic
makes it possible to call the method from anywhere. More on this later, but for now all of our methods will bepublic
. -
The
static
keyword basically means that the method belongs to the class and not an object. That will make more sense in the next chapter, but for now our methods will bestatic
. -
The
void
keyword indicates that this method will not return anything. This is called the method’s return type, and we’ll learn about this shortly. -
displayCopyright
is the identifier for the method, in the same way variables have identifiers. Like variable identifiers, use camelCase to make the name readable—and make the name descriptive. The convention is that the name of a method should describe what it does; usually, that means the identifier is (or includes) a verb. -
The parentheses indicate to the compiler that this is a method, as opposed to a variable or some other fancy thing. You’ll see what we can put in the parentheses shortly.
3.2. Variable Scope
As we begin organizing our code into different methods and (when we learn object-oriented programming basics) classes, we’ll need to understand how data is compartmentalized within a program. Whenever we create a class or method—and other structures we’ll learn as we go—we use curly braces to define the boundaries and indenting to help make those boundaries clear. These braces form code blocks.
The outermost code block is our class.
Although there are a few things that can go outside the class, like package
and import
statements, the class code block contains all of the components of our program.
In some cases we can place one block inside another, as such as putting a method inside a class. This is called nesting blocks, and a nested block must be completely enclosed; in other words, a method can’t be partly in a class and partly out of it.
And some kinds of blocks can’t be nested. A method can be nested inside a class, but a method cannot be nested inside another method. Many IDEs, including Visual Studio Code use color coding to make code blocks more clear.

A variable can only be used or accessed inside the block in which it was declared, or within a block nested within that block; this is the variable’s scope
.
When we refer to a variable, the compiler checks within that code block, or scope, to see if the variable has been declared.
If it doesn’t find a variable with that identifier within the current scope, it will move out to the enclosing code block (if it is nested within a class, for example) and check there.
If the variable is still not found, the compiler stops and produces an error.
Basically, referring to a variable that is declared in a different scope is the same as referring to a variable we never declared at all. Trying to use a variable in a different code block is referred to as an out of scope reference.
ScopeExample.java
. An example of code with an out-of-scope variable reference. 1
2
3
4
5
6
7
8
9
10
11
12
13
public class ScopeExample {
public static void main(String[] args) {
int favoriteNumber = 7;
System.out.println(favoriteNumber); (1)
outputNumber();
}
public static void outputNumber() {
System.out.println(favoriteNumber); (2)
}
}
1 | This is a valid, or in scope, reference because favoriteNumber is declared within main() . |
2 | This is an invalid out of scope reference because favoriteNumber can only be accessed within main() . |
3.2.1. Variable Shadowing
When we first started using variables, we learned that we can’t make two variables with the same name, but it’s a little more nuanced than that. We can’t make two variables with the same name and scope. Java will allow us to declare a variable with the same name in a different scope, which is called variable shadowing. Shadowing is a very bad practice, because it often leads to confusion about which variable is in scope (though we’ll see an exception down the road).
The example below can be confusing to beginners and to people who are reading the code quickly.
When outputNumber()
is called, another variable named favoriteNumber
is created and assigned the value 18
.
After that is output, an assignment statement changes that value to 10
.
Then, program execution returns to main()
, where a println()
statement outputs favoriteNumber
again.
However, this favoriteNumber
wasn’t changed to 10—the other one was.
ShadowingExample.java
. An example of variable shadowing, which we should avoid. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ShadowingExample {
public static void main(String[] args) {
int favoriteNumber = 7;
System.out.println(favoriteNumber); (1)
outputNumber();
System.out.println(favoriteNumber); (2)
}
public static void outputNumber() {
int favoriteNumber = 18;
System.out.println(favoriteNumber); (3)
favoriteNumber = 10;
}
}
1 | This outputs 7 |
2 | This outputs 18 , because it refers to the variable declared in outputNumber() |
3 | This still outputs 7 because the change to 10 is made to the favoriteNumber within the outputNumber() method. |
3.2.2. Global Variables
As you can see, variable scope has a big impact on how our code runs. Beginning programmers sometimes try to avoid scope issues by declaring their variables within the class code block, which makes them accessible to any block nested within the class—inclusing all of the methods the class encloses. This kind of class-level variable is sometimes called a global variable, and the use of global variables is generally discouraged.
GlobalVariableExample.java
. An example of a global variable, which we should not use. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class GlobalVariableExample {
static int favoriteNumber = 7; (1)
public static void main(String[] args) {
System.out.println(favoriteNumber);
outputNumber();
System.out.println(favoriteNumber);
}
public static void outputNumber() {
System.out.println(favoriteNumber);
favoriteNumber = 18; (2)
}
}
1 | Declaration at the class level. Note that global variables must be static . |
2 | This changes the value of favoriteNumber to 18 for all methods in the program. |
Instead, we’ll declare all of our variables within our methods; these are called local variables.
The use of global or class-level variables in code that you turn in for an assignment in my class is very heavily penalized. As much as possible, I try to reinforce best practices—and that means minimizing the use of global variables. |
Of course, this presents a problem. What if we need access to a variable in another method? The best practice is to pass that variable value to the method as needed, and for the method to pass back a value when necessary.
In the next chapter, we will start using variables that look a lot like the global variables I just said we shouldn’t use. To be clear, those instance variables behave differently and serve a different purpose. They are global variables as described here. |
3.3. Passing Data to Methods
Sometimes a method needs some information in order to carry out its purpose.
For example, the print()
method needs to know what it’s supposed to print.
To provide information to a method, we pass the information in as arguments.
So, the String
we want to output is passed to the print()
method as an argument, and arguments are always placed inside the parentheses:
System.out.print("Hello World");
In this example, "Hello World" is an argument.
We establish what information a method needs as part of the method definition. Within the method we’re defining, those pieces of information are called parameters. A parameter is a variable that exists in the method and receives the argument, and it’s declared inside the parentheses in our method definition. The methods we’ve defined so far didn’t need any outside information, so we haven’t been putting anything in the parentheses—but now let’s see an example with a parameter.
1
2
3
4
5
6
7
8
9
10
11
public class ParameterExample {
public static void main(String[] args) {
outputGreeting("Tim"); (1)
}
public static void outputGreeting(String name) { (2)
System.out.println("Hello, " + name + "!");
}
}
1 | "Tim" is the argument. |
2 | name is the parameter. |
In the above example, "Tim" is passed to the outputGreeting()
method as an argument.
Within that method, the parameter name
stores the argument, so when this code runs, name
is equal to "Tim".
The actual value passed in when we call a method is referred to as an argument. The variable that receives that value within the method is referred to as a parameter. |
3.4. Returning Values
The methods we’ve seen to this point are basically commands—they simply perform a task, and then when they’re done, program execution just goes back to the method that called it and resumes there. But we can also create methods that are like questions—they execute a chunk of code, but when they are finished they give back an answer.
Consider these methods:
1
2
3
4
5
6
7
8
9
public static void printFavNum() { (1)
int favNum = 10 - 3;
System.out.print(favNum);
}
public static int getFavNum() { (2)
int favNum = 10 - 3;
return favNum;
}
1 | This specifies a return type of void |
2 | This specifies a return type of int |
The first method is a command to print out a favorite number, so it does not return anything.
The void
in the method header is the return type, and void basically means nothing; this method returns nothing.
The second method is asking to get a favorite number, so it is going to give back an int
. The return type is specified as int
.
The return
statement sends the favNum
value back to the method that called getFavNum()
.
If a method has a return type of anything other than void , it will only compile if it has a return statement followed by a value—either literal or variable—of the specified type.
|
This means that methods themselves essentially have data types.
printFavNum()
has a data type of void
.
getFavNum()
has a data type of int
.
Since methods have types, we can use them in statements just as we’d use a literal or variable of that type.
For example, the following line of code is valid:
int answer = 18 + getFavNum();
This evaluated the same way as any other assignment statement. It starts on the right and finds that method call, so it will execute getFavNum()
and plug the returned value into the operation, resulting in 18 + 7
and ultimately evaluating to 25
, which is then assigned to answer
.
A return
statement in a void
method stops execution of the method and returns to the calling method.
1
2
3
4
5
public static void shortCircuit() {
System.out.print(“This line of code runs...”);
return;
System.out.print(“This can never run!”);
}
The second print() statement won’t execute because the return statement ends the method. The compiler doesn’t like these kinds of unreachable statements, though, so it will not compile.
return
statements in void
methods will have some uses for us later on.
A Java method can only return one piece of data, so it can only have one return type. |
3.4.1. Returning vs. Outputting
Generally speaking, it’s better to return values from a method rather than outputting values.
There are a few reasons for this, but consider an obvious one.
If we use a print()
method, our code is limited to only working in a console application.
That’s fine for now, because it’s the only kind of application we know how to make!
But what if we want to use that same code in a web application, or a mobile app?
That print()
statement won’t work—rather, the user will never see the result, because they won’t have a console window.
Consider this code:
1
2
3
4
5
6
7
8
9
10
public class BadOutput {
public static void main(String[] args) {
kingOfSoul();
}
public static void kingOfSoul() {
System.out.println("Otis Redding");
}
}
If the kingOfSoul()
method knows who the King of Soul is, how do we print that out if we can’t perform the output inside the method?
The solution is to return the String and perform the output in main()
.
1
2
3
4
5
6
7
8
9
10
public class GoodOutput {
public static void main(String[] args) {
System.out.println(kingOfSoul());
}
public static String kingOfSoul() {
return "Otis Redding";
}
}
This is another example of something that seems annoying, like it’s just extra work. When we’re learning new things, we sometimes have to accept the wisdom of people who are experienced—and recognize that eventually we’ll see the point. We’re all about learning good habits and best practices around here, so we’ll almost always return values rather than printing them.
There are times when we want a method whose sole purpose is to produce some output. In that case, we should give it an appropriate identifier. Notice that those kinds of methods in my examples have print or output in the name.
On assignments, I rarely want students to create methods that produce output, and when I do I always make that explicit in my directions.
When I refer to returning something, I mean just that.
The rule of thumb is, all input and output statements should be in the main()
method and data should be passed around as necessary.
I strongly penalize input and output statements outside of the main() method because I’m trying to build habits that will serve you well as you learn more about programming.
|
The Lab Assignments in Canvas can be completed using what we’ve covered to this point. You might choose to complete that work now, then move onto the next section—which you’ll need for the Programming Project. |
3.5. Overloading a Method
Sometimes the task, action, or calculation that a method produces has different ways of operating depending on the circumstances.
Consider a method that calculates the average age of two people:
1
2
3
public static double averageAge(int age1, int age2) {
return (double) (age1 + age2) / 2;
}
This is a pretty straightforward method.
Notice that the return statement uses casting with (double)
to ensure that the result is not truncated.
If we want to calculate an average age of 3 people, we could almost use the same method. We want a method that still calculates the average age, but takes three arguments and divides by 3, instead of 2.
To create another version of a method that operates a little differently, we can use method overloading.
To overload a method, we write a new method with the same identifier, but with a different set of parameters.
An overload for our averageAge()
method could look like this:
1
2
3
public static double averageAge(int age1, int age2, int age3) {
return (double) (age1 + age2 + age3) / 3;
}
Note that the method identifier is exactly the same, but this version accepts three int
arguments instead of two.
That difference allows the compiler to easily determine which implementation of the method is being called: if there are two `int`s in the parenthesis, it calls the first implementation, and if there are three `int`s, it calls the second implementation.
When we’re using the method, we can call whichever best suits our needs at the time.
The compiler can also easily distinguish overloaded methods if the types of the parameters are different. An implementation that accepts `double`s is valid:
1
2
3
public static double averageAge(double age1, double age2, double age3) {
return (double) (age1 + age2 + age3) / 3;
}
If the compiler sees a call to averageAge()
with three double
values, it will invoke this last version.
3.5.1. Incorrect Overloading
Overloaded methods must have differences in the number and/or types of the parameters. The names of those parameters doesn’t differentiate them, so different names is not enough to make a valid overload.
BadOverloading.java
. An invalid example of overloading. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class BadOverloading {
public static void main(String[] args) {
System.out.println(area(15, 10)); (1)
}
// Calculates area of a rectangle
public static double area(double length, double width) {
return length * width;
}
// Calculates area of an oval
public static double area(double smallRadius,
double bigRadius) {
double area = 3.14 * smallRadius * bigRadius;
return area;
}
}
1 | The compiler can’t tell if we want the area implementation of a rectangle of the implementation for an oval. |
The term we use to describe a method’s identifier and parameter list (the number, order and types of parameters) is a method signature. The method signature must be unique so the compiler can identify which method code to run.
AverageAge.java
. A valid example of method overloading.public class AverageAge {
public static void main(String[] args) {
System.out.println(averageAge(1.25, 1.5, .5)); (1)
System.out.println(averageAge(10, 20)); (2)
System.out.println(averageAge(10, 20, 25)); (3)
}
public static double averageAge(int age1, int age2) {
return (double) (age1 + age2) / 2;
}
public static double averageAge(int age1, int age2, int age3) {
return (double) (age1 + age2 + age3) / 3;
}
public static double averageAge(double age1, double age2, double age3) {
return (double) (age1 + age2 + age3) / 3;
}
}
1 | The compiler sees three double values, so it calls the third implementation. |
2 | The compiler sees two int values, so it calls the first implementation. |
3 | The compiler sees three int values, so it calls the second implementation. |
3.6. Solution Walkthrough
In "solution walkthrough" videos, I give a problem/prompt that is similar to the kinds of work I assign, and then I record myself writing a solution. It’s not absolutely mandatory to watch this video, but students report that these videos are particularly helpful.
Check Yourself Before You Wreck Yourself (on the assignments)
Can you answer these questions?
Sample answers provided in Stuff That’s Tacked On The End.