Methods
A method is a named, reusable block of code that performs a single well-defined task. Well-designed methods eliminate repetition, make code testable, and allow large programs to be built from small, understandable pieces.
Why Methods?
Imagine calculating the average mark in five different places in your program. Without methods, you copy the same logic five times. When a bug is found or the formula changes, you must update five places. With a method, you fix it once. This principle — Don't Repeat Yourself (DRY) — is one of the most important in software engineering.
Anatomy of a Method
// access static return-type name parameters
public static int add (int a, int b) {
return a + b; // return statement sends a value back to the caller
}
// Calling the method:
int result = add(10, 25);
System.out.println("Sum: " + result); // 35
// The values you pass are called arguments:
int x = add(100, 200); // 100 and 200 are the arguments
// Inside the method, a=100 and b=200 are the parameters
void Methods (No Return Value)
If a method does a job without producing a result (like printing output), use void as the return type. A void method must not have a return value; statement (though a bare return; to exit early is allowed).
public static void printLearnerInfo(String name, int age, String course) {
System.out.println("=".repeat(30));
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Course: " + course);
System.out.println("=".repeat(30));
}
// Calling it — no assignment needed since there's no return value
printLearnerInfo("Thandi", 21, "Java");
printLearnerInfo("Sipho", 24, "Python");
Return Types
A non-void method must execute a return statement for every possible path through the method. The compiler checks this — if there is any code path that could reach the end without returning, it is a compile error.
// Returns a String — every path must return a String
public static String gradeLabel(int mark) {
if (mark >= 80) return "Distinction";
if (mark >= 70) return "Merit — Upper";
if (mark >= 60) return "Merit";
if (mark >= 50) return "Pass";
return "Not yet competent"; // the else branch — required!
}
// Returns a double — calculating average
public static double average(int[] marks) {
int total = 0;
for (int m : marks) total += m;
return (double) total / marks.length;
}
// Usage
System.out.println(gradeLabel(74)); // Merit
System.out.println(gradeLabel(91)); // Distinction
System.out.printf("Average: %.1f%%%n", average(new int[]{65, 72, 80}));
Method Overloading
Java allows multiple methods with the same name, as long as their parameter lists differ (different types, different number of parameters). The compiler chooses the correct one based on the arguments you pass. The return type alone cannot distinguish overloaded methods.
// Three overloaded add methods
public static int add(int a, int b) { return a + b; }
public static double add(double a, double b) { return a + b; }
public static int add(int a, int b, int c) { return a + b + c; }
System.out.println(add(3, 4)); // calls int version → 7
System.out.println(add(3.0, 4.0)); // calls double version → 7.0
System.out.println(add(3, 4, 5)); // calls 3-param version → 12
Passing Values vs Passing References
Java is always pass-by-value. But for objects and arrays, the "value" being passed is the reference (memory address). This means:
- Primitives (
int,double, etc.) — changes inside the method do not affect the original. - Arrays and objects — changes to the content inside the method affect the original, but reassigning the variable itself does not.
public static void tryToDouble(int x) {
x = x * 2; // only affects the local copy
}
public static void doubleAll(int[] arr) {
for (int i = 0; i < arr.length; i++) {
arr[i] *= 2; // modifies the actual array — same memory
}
}
int n = 5;
tryToDouble(n);
System.out.println(n); // still 5
int[] marks = {10, 20, 30};
doubleAll(marks);
System.out.println(java.util.Arrays.toString(marks)); // [20, 40, 60]
Static vs Instance Methods
All the methods above are static — they belong to the class, not to any specific object. You call them on the class directly. When you learn about classes and objects in Lesson 11, you will write instance methods that belong to individual objects and can access object-specific data.
Practice Task
Your Turn
Write a class MathUtils with the following static methods: (1) max(int a, int b) returning the larger value, (2) min(int[] values) returning the smallest in an array, (3) isPrime(int n) returning a boolean, (4) factorial(int n) returning a long (handle n=0 as a special case returning 1). Test each from main with several inputs including edge cases.
Common Mistakes
- Forgetting the
returnstatement in a non-void method — the compiler will catch it, but understand why every code path needs one. - Returning the wrong type — if a method declares
intbut you return adouble, it is a compile error (or a silent truncation with a cast). - Methods that do too many things — a method should do one thing well. If you can't describe it in a short phrase, split it.
- Recursive methods without a base case — calling a method that calls itself indefinitely causes a
StackOverflowError. - Calling an instance method from
static mainwithout creating an object — you will get a compile error. Static methods cannot access instance state.
Professional Tip
Name every method with a verb phrase that describes what it does: calculateAverage, printReport, isEligible. A method named data or process tells the reader nothing.
Mini Quiz
What does method overloading mean in Java?