What you'll learn
As programs grow, cramming everything into main becomes a tangled mess. Methods let you break a program into small, named, reusable pieces — the single most important skill for writing code that stays understandable.
By the end you'll be able to:
- Define and call methods with parameters and return values
- Understand variable scope
- Provide several versions of a method with overloading
- Explain Java's pass-by-value behaviour — the interview classic
- Accept a flexible number of arguments with varargs
- Write recursive methods that call themselves
- Design clean, single-purpose methods
Defining & calling methods
A method is a named block of code that performs one task. You define it once and call it as many times as you like. Every method has the same shape:
public static int add(int a, int b) {
return a + b;
}Modifiers — who can call it and how (public, static).
Return type — the type it hands back (void if nothing).
Name — a verb describing what it does.
Parameters — the inputs it needs to do its job.
A method can take parameters (inputs) and hand back a result with return. If it doesn't return anything, its return type is void. The values you actually pass in when calling are called arguments.
public class Greeter {
static void greet(String name) { // void: returns nothing
System.out.println("Hello, " + name + "!");
}
static int square(int n) { // returns an int
return n * n;
}
public static void main(String[] args) {
greet("Sara"); // call it
greet("Omar"); // reuse it
int result = square(5);
System.out.println("5 squared is " + result);
}
}Tip
calculateTax, isValidEmail, and sendReceipt tell the whole story without you reading the body.Local variables & scope
A variable declared inside a method (or a block { }) is local — it exists only there and vanishes when the method ends. Two methods can each have a variable called total without any conflict, because each lives in its own scope. This isolation is what makes methods safe to reuse.
Method overloading
Java lets you give several methods the same name as long as their parameter lists differ (in number or types). This is overloading, and the compiler picks the right version based on the arguments you pass:
static int add(int a, int b) { return a + b; }
static double add(double a, double b) { return a + b; }
static int add(int a, int b, int c) { return a + b + c; }
System.out.println(add(2, 3)); // 5 -> int version
System.out.println(add(2.5, 3.5)); // 6.0 -> double version
System.out.println(add(1, 2, 3)); // 6 -> three-arg versionNote
System.out.println is itself heavily overloaded, which is why it happily prints ints, doubles, strings, and objects.Pass-by-value in Java
Here's a concept that confuses even experienced developers: Java is always pass-by-value. When you call a method, it receives a copy of each argument.
Primitives → a copy of the value
The method gets its own copy. Changing the parameter never affects the caller's variable.
Objects → a copy of the reference
Both variables point to the same object, so changes to its contents are visible. (Reassigning the parameter still doesn't affect the caller.)
For a primitive, that copy is the value, so the original is untouchable. For an object, the copy is the reference (the arrow pointing to the object) — so both the caller and the method point at the same object, and changes to its contents are shared:
static void tryToChange(int x) {
x = 99; // changes only the local copy
}
static void fillFirst(int[] list) {
list[0] = 99; // changes the shared array's contents
}
public static void main(String[] args) {
int number = 5;
tryToChange(number);
System.out.println(number); // still 5
int[] data = {1, 2, 3};
fillFirst(data);
System.out.println(data[0]); // now 99
}Key idea
number stayed 5, but the array's contents changed. Both variables shared one array — yet neither could reassign the other's variable. That's pass-by-value in a nutshell.Variable-length arguments (varargs)
Sometimes you don't know how many arguments there'll be. Varargs — Type... name — lets a method accept any number of them, treating them as an array inside:
static int sum(int... numbers) { // accepts any count
int total = 0;
for (int n : numbers) total += n;
return total;
}
System.out.println(sum(1, 2, 3)); // 6
System.out.println(sum(10, 20, 30, 40)); // 100
System.out.println(sum()); // 0Note
String.format accept any number of values.Recursion
A recursive method is one that calls itself to solve a smaller version of the same problem. Every recursion needs two things: a base case that stops it, and a recursive case that moves toward that base case. The classic example is factorial:
static int factorial(int n) {
if (n <= 1) return 1; // base case: stops the recursion
return n * factorial(n - 1); // recursive case
}
System.out.println(factorial(5)); // 5*4*3*2*1Calls go down (the stack grows)
Returns come back up (the stack unwinds)
Always have a base case
StackOverflowError.Clean method design
A few habits separate readable code from a mess:
- One responsibility — each method should do a single, well-defined job
- Short — if a method scrolls off the screen, it probably wants splitting
- Descriptive names — verbs that state the effect (
saveOrder, notdoStuff) - Few parameters — many parameters is a hint the method is doing too much
- Return early — handle edge cases up top to avoid deep nesting
Tip
Recap & quick check
Key takeaways
- Methods package code into named, reusable pieces with parameters and an optional return value.
- Local variables live only inside their method or block (scope).
- Overloading = same name, different parameter lists; the compiler picks the match.
- Java is always pass-by-value: primitives copy the value, objects copy the reference.
- Recursion needs a base case to stop and a recursive case that shrinks the problem.
Quick check
1. What return type does a method use when it returns nothing?
2. How does Java pass arguments to methods?
3. What makes two methods valid overloads?
4. What does every recursive method need to avoid running forever?
5. After passing a primitive int into a method that reassigns it, the caller's variable is…
Superb — you can now structure programs into clean, reusable pieces. Next up: Module 7 — Arrays, where you'll store and process whole collections of values.