Java Methods
A method is a named block of code that performs a task and can be run whenever it is needed by calling its name. Methods let you write logic once and reuse it, break a large program into small understandable pieces, and give each piece a name that describes what it does. In Java, every method belongs to a class.
Defining and Calling a Method
public class Greeter {
static void sayHello() {
System.out.println("Hello!");
System.out.println("Welcome to the course.");
}
public static void main(String[] args) {
sayHello();
sayHello();
}
}
Output:
Hello!
Welcome to the course.
Hello!
Welcome to the course.
sayHello is defined once and called twice. A call is the method name followed by parentheses. When the call runs, execution jumps into the method, runs its body, then returns to the statement after the call.
Anatomy of a Method Declaration
public static double calculateArea(double width, double height) {
return width * height;
}
| Part | Here | Meaning |
|---|---|---|
| Access modifier | public | Who may call the method (public, protected, private, or package-private if omitted) |
static (optional) | static | The method belongs to the class, not to an individual object |
| Return type | double | The type of value the method gives back; void if none |
| Name | calculateArea | camelCase, usually a verb describing the action |
| Parameter list | (double width, double height) | Inputs, each with a type and a name; may be empty () |
| Body | { return width * height; } | The statements that run when the method is called |
The name together with the parameter types (calculateArea(double, double)) is the method's signature. Two methods in the same class cannot have the same signature.
Parameters and Arguments
Parameters are the variables listed in the method declaration. Arguments are the actual values passed when calling it.
static void greet(String name, int times) { // name, times: parameters
for (int i = 0; i < times; i++) {
System.out.println("Hi, " + name);
}
}
greet("Ada", 2); // "Ada", 2: arguments
Arguments must match the parameters in number, order, and type. greet(2, "Ada") and greet("Ada") are compile errors. Parameters are covered in detail in the next lesson.
Return Values
A method with a non-void return type must send back a value of that type using return:
static int square(int n) {
return n * n;
}
int result = square(7); // 49
System.out.println(square(3) + 1); // 10
The call square(7) is an expression whose value is whatever the method returns, so it can be stored, printed, or used in further calculations. return also ends the method immediately. A void method returns nothing but can use a bare return; to exit early. Return values have their own lesson.
The Call Stack
Each method call gets its own stack frame: a private area holding its parameters and local variables. When the method returns, its frame is discarded.
static int add(int a, int b) {
int sum = a + b;
return sum;
}
public static void main(String[] args) {
int x = 5;
int total = add(x, 10);
System.out.println(total); // 15
}
main() calls add(5, 10)
┌───────────────┐
│ add: a=5, b=10│ <- new frame created
│ sum=15 │
└───────────────┘ <- frame discarded when add returns 15
main: x=5, total=15
This is why a method's local variables are not visible from outside it, and why the same method can be called many times (even recursively) without the calls interfering with each other. When an exception is thrown, the stack trace it prints is a list of these frames, showing the chain of calls that led to the error.
static Versus Instance Methods
A static method belongs to the class and is called without creating an object. An instance method (no static) belongs to an object and can use that object's fields.
public class Counter {
private int count; // each Counter object has its own count
public void increment() { // instance method: uses this object's state
count++;
}
public int getCount() {
return count;
}
public static int add(int a, int b) { // static: needs no object state
return a + b;
}
}
Counter c = new Counter(); // create an object
c.increment(); // instance method: called on an object
c.increment();
System.out.println(c.getCount()); // 2
System.out.println(Counter.add(3, 4)); // static: called on the class, 7
A static method cannot call an instance method or read an instance field directly, because there is no particular object for it to use:
public class Demo {
void hello() { System.out.println("hi"); }
public static void main(String[] args) {
hello(); // compile error: non-static method cannot be referenced from a static context
new Demo().hello(); // works: create an object, then call
}
}
This is why the early examples in this tutorial mark helper methods static: they are called from main, which is static. Once you start writing classes in the OOP section, most methods will be instance methods.
Why Methods Matter
Removing duplication
Without methods, the same logic gets copied wherever it is needed, and every copy must be fixed when a bug is found:
// Duplicated
double priceA = 1200 * 1.18;
double priceB = 450 * 1.18;
double priceC = 89 * 1.18;
// One method, one place to change the tax rule
static double withTax(double amount) {
return amount * 1.18;
}
double priceA = withTax(1200);
Naming intent
A well-named method turns a block of code into a single readable step:
if (isValidEmail(input) && !isBlocked(input)) {
sendWelcome(input);
}
The reader understands what happens without reading how each check is done.
Testing and reuse
A method that takes inputs and returns an output can be tested on its own, called from several places, and moved into a shared utility class.
Designing Good Methods
- One task per method. If a name needs "and" (
validateAndSave), it probably does two things and could be split. - Name with a verb.
calculateTotal,sendEmail,findUser. Methods returning booleans read as questions:isEmpty,hasAccess,canRetry. - Keep them short. A method that fits on a screen is easy to understand fully. Long methods are usually several methods waiting to be extracted.
- Prefer returning results over printing them. A method that returns a value can be printed, logged, tested, or used in another calculation. One that prints directly can only print.
Method Overloading (Preview)
Several methods in one class may share a name if their parameter lists differ:
static int max(int a, int b) { return a > b ? a : b; }
static double max(double a, double b) { return a > b ? a : b; }
static int max(int a, int b, int c) { return max(max(a, b), c); }
The compiler picks the version matching the argument types and count. Overloading has its own lesson in the OOP section.
Practical Example: Invoice Calculator
public class Invoice {
static final double GST_RATE = 0.18;
static double lineTotal(double unitPrice, int qty) {
return unitPrice * qty;
}
static double discount(double subtotal) {
if (subtotal >= 10_000) return subtotal * 0.10;
if (subtotal >= 5_000) return subtotal * 0.05;
return 0;
}
static double gst(double amount) {
return amount * GST_RATE;
}
static void printRow(String label, double value) {
System.out.printf("%-12s %10.2f%n", label, value);
}
public static void main(String[] args) {
double subtotal = lineTotal(2500, 2) + lineTotal(799, 4) + lineTotal(1200, 1);
double disc = discount(subtotal);
double taxable = subtotal - disc;
double tax = gst(taxable);
printRow("Subtotal", subtotal);
printRow("Discount", -disc);
printRow("GST 18%", tax);
printRow("Total", taxable + tax);
}
}
Output:
Subtotal 9396.00
Discount -469.80
GST 18% 1606.72
Total 10532.92
Each method does one job and has a name that explains it. main reads as a summary of the calculation, while the details (discount tiers, tax rate, formatting) live in their own methods. Changing the discount rules means editing only discount; changing the output layout means editing only printRow. lineTotal, discount, and gst return values instead of printing, so main can combine them freely.