SwadhyAI Notes

All Java notes

Java Methods

›Short versionOpen if you only have a minute.
  • A method names one piece of work: parameters in, a body, and either a returned value or void.
  • The signature the compiler uses for overloading is the name plus the parameter types, in order.
  • Each call pushes a stack frame. Parameters and locals belong to that call, then disappear on return.
  • A non-void method must return a matching value on every path. A void method returns by finishing.
  • The caller decides what to do with a returned value. Side effects happen whether or not the caller uses the result.

A checkout path subtracts the coupon before tax. A refund path subtracts it after. Both snippets look reasonable alone, and the receipt and the ledger stop agreeing. The arithmetic was copied, then one copy drifted.

A gives that arithmetic one name and one body. Callers pass the price and the coupon. They receive the amount due. When the rule changes, it changes in the method, and every call site follows.

What a call does

main reaches applyDiscount(1000, 150) and pauses. The call creates a for applyDiscount. Inside it, price is 1000, discount is 150, and finalPrice becomes 850. return hands 850 back, pops that frame, and main stores the value in total.

Checkout.java
public class Checkout {
    static int applyDiscount(int price, int discount) {
        int finalPrice = price - discount;
        return finalPrice;
    }

    public static void main(String[] args) {
        int total = applyDiscount(1000, 150);
        System.out.println(total);
    }
}

The names price and discount exist only inside that call. After the return, main still has total. It does not have finalPrice. A second call, applyDiscount(400, 25), pushes another frame with another pair of parameters. The first call’s locals are already gone.

Terminal
$ javac Checkout.java
$ java Checkout
850

The declaration

Every method sits inside a class. The header is the contract the compiler checks at each call. The body is the statements that run when a call is accepted.

java
static int applyDiscount(int price, int discount) {
    int finalPrice = price - discount;
    return finalPrice;
}

static means the call does not need an object of the class. The here is int. The name is applyDiscount. The two are price and discount, both int. Together, the name and those parameter types are the . The parameter names are for the body and for readers. Call sites match by position and type, so a caller cannot pass the discount first and expect the names to sort it out.

A method uses the same shape when the useful outcome is an effect rather than a value. printLogin writes a line and finishes. There is nothing to assign.

java
static void printLogin(String username) {
    System.out.println(username + " logged in");
}

Choose the return type from what the caller must be able to do next. A method that decides whether a mark is passing should return boolean, so the caller can branch, store the answer, or pass it on. A method whose job is to write a line can be void. Mixing both jobs in one method forces every caller to accept the printing, even a caller that only wanted the decision.

Returning on every path

square promises an int. Computing result is not enough. A path that reaches the closing brace without a return is a compile error, because the caller would have no value to continue with.

java
static int square(int n) {
    int result = n * n;
    return result;
}

When a method branches, each path that can finish the method must return. An if that returns a grade, with an else that returns a different grade, covers the method. An if that returns only for the passing case leaves the failing case unfinished, and the compiler rejects it.

A return leaves immediately. Statements written after it on that same path are unreachable, and unreachable code is a compile error too. In a void method, return; is the early exit. Falling off the last line is the normal exit.

java
static boolean isValidEmail(String email) {
    return email != null && email.contains("@");
}

square computes n * n into result and then the method ends, with no return. The parameter and the arithmetic are fine. What does the compiler do?

It rejects the method. The return type is int, so every path must return an int. A local variable holding the answer is not a return. The frame would have nowhere to put a value for the caller.

What belongs in the method

A useful method is small enough that its name still describes the body. applyDiscount subtracts. It does not also format the receipt. The caller that needs a receipt calls a second method and passes the amount. Each frame stays easy to read in a debugger: a few parameters, a few locals, one return.

Instance methods and static methods differ in whether a call has an object to work on. That choice is the next design decision after the signature, and it has its own page. So do parameters, pass-by-value, overloading, and recursion. They all sit on this model: a named body, a checked signature, and a fresh frame per call.