java-foundations 15 min read

Static Methods — A First Look

Reusable named code: headers, parameters, returns, calls, and how scope works

Reading: Reges & Stepp: Ch. 1 (procedural decomposition), Ch. 3 §3.1

You have been calling methods all quarter — System.out.println, Math.sqrt, s.length(), Integer.parseInt, sc.nextLine(). Every time you put a name, a dot, and () together, you made a method call. Now you will write your own. This is a first-look lesson; a later unit revisits methods in depth. The basics belong here because you will use them in every lab from this point on.

In a nutshell

A method is a named piece of code you can run from somewhere else by writing its name and (). A static method is the simplest kind: you call it on the class name itself, no objects required.

Methods exist for two reasons. First, code reuse — write a computation once, call it from twenty places. Second, decomposition — break a long main into small named pieces that each do one understandable thing.

By the end of this lesson you will be able to read a method header, explain the difference between a parameter and an argument, trace a method call by hand (watching values flow in and out), and understand why a variable declared in one method is invisible inside another.

Quick reference

Anatomy of a static method

public static  int   square  (int n)    { return n * n; }
//      ^       ^    ^        ^          ^
//   modifiers  return name   parameter   body
//              type          list

Terminology

Term Meaning Example
Method header The first line: modifiers, return type, name, parameter list public static int square(int n)
Return type Type of the value the method gives back, or void for none int
Method name camelCase convention square, ageInYears
Parameter The variable in the method definition int n
Argument The value passed at the call site 5 in square(5)
Call / invoke Running the method square(5)
return statement Ends the method and produces the value return n * n;
void “No return value”; the method ends at } or a bare return; public static void greet() { ... }

Calling a method

int result = square(5);          // passes 5; result gets 25
System.out.println(square(7));   // passes 7; prints 49

A call to a non-void method is an expression — it produces a value you can assign, print, or use inside a bigger expression.


Deep dive

1. Why methods exist — decomposition and reuse

Here’s a program that prints three different labeled banners:

public static void main(String[] args) {
    System.out.println("**********************");
    System.out.println("*     Welcome!       *");
    System.out.println("**********************");

    // ... other code ...

    System.out.println("**********************");
    System.out.println("*     Session 2      *");
    System.out.println("**********************");

    // ... other code ...

    System.out.println("**********************");
    System.out.println("*     Goodbye!       *");
    System.out.println("**********************");
}

Three copies of the same “print a boxed message” pattern. If you widen the box, you have to change three places. A typo in one breaks consistency. This is exactly the problem methods solve.

Factor out the pattern:

public static void printBox(String message) {
    System.out.println("**********************");
    System.out.println("* " + message + " *");
    System.out.println("**********************");
}

public static void main(String[] args) {
    printBox("Welcome!     ");
    printBox("Session 2    ");
    printBox("Goodbye!     ");
}

Same output. Nine lines of main became three. Change the box once; every caller gets the new version. That’s code reuse.

It’s also decomposition. main now reads like a table of contents: welcome, session 2, goodbye. The reader scanning main sees the program’s shape in one glance. The details of how each banner prints are tucked inside printBox, where you look only when you care.

Self-check. Why not just copy-paste the three println lines everywhere? Give two concrete reasons.

Answer

(1) Changes require editing in multiple places and you will forget one. (2) Each copy is another opportunity for a typo, so the copies drift apart silently.

2. Method anatomy — headers, parameters, returns

Here’s a method with parameters and a return value:

public static int max(int x, int y) {
    if (x > y) {
        return x;
    } else {
        return y;
    }
}

Label every part:

  • public — a modifier. For now: “this method can be called from anywhere.” (More in Week 5.)
  • static — another modifier. Means the method belongs to the class rather than to any particular object. That is why you call it on the class name: MyClass.max(3, 7).

static is not final. These two modifiers get confused constantly because they both show up in front of method and field declarations. They do unrelated jobs:

  • static controls who owns it: static = belongs to the class, call on the class name, no object needed. Non-static = belongs to an instance, requires an object.
  • final controls whether it can change or be overridden: final on a variable means “cannot be reassigned after initialization.” final on a method means “subclasses cannot override it.” final on a class means “cannot be subclassed.”

A method can be static alone, final alone, both (public static final int MAX = 100; is a classic constant declaration), or neither. Same with fields. They do not imply each other.

  • int — the return type. This method hands back an int.
  • max — the method name. Use a name that describes the answer it returns.
  • (int x, int y) — the parameter list. Two int inputs, which the method calls x and y.
  • { ... } — the method body.
  • return x; / return y;return statements. Each one ends the method and produces the value that gets sent back.

A method that doesn’t produce a value uses void:

public static void greet(String name) {
    System.out.println("Hi, " + name);
}

void methods do work (like printing) and then end. printBox above is a void method.

Parameter vs argument. These words are not synonyms. The parameter is the variable in the method definition — int n in square(int n). The argument is the value you pass at the call site — the 5 in square(5). When the call happens, Java takes the argument and assigns it to the parameter. You’ll hear people use these words interchangeably in casual speech, but the distinction matters when you are debugging.

Check Your Understanding
Given public static int max(int x, int y) { ... } and the call max(5, 3), which is the argument?
AThe value 5
BThe variable int x in the header
CThe name max
DThe return type int
Answer: A. Argument = the value supplied at the call site. 5 is a value. int x is the parameter — the variable inside the method that receives the value. When the call runs, Java assigns x = 5 and y = 3 inside max.

Self-check. What is the return type of Integer.parseInt? Its parameter list?

Answer

Return type: int. Parameter list: (String s). You have been calling it as Integer.parseInt(sc.nextLine()) all quarter: the String returned by nextLine() is the argument; the int returned by parseInt is what you store in a variable.

3. Calling, tracing, and scope

Here is what happens step by step when you call a method:

public static int square(int n) {
    return n * n;
}

public static void main(String[] args) {
    int a = 5;
    int result = square(a);
    System.out.println(result);
}

Trace:

  1. main starts. Java creates a local variable a = 5.
  2. Java evaluates the argument a in square(a) to get the value 5.
  3. Java calls square, creating a new local variable n inside the method and assigning it the value 5. n is a copy of the argument.
  4. The body runs: return n * n evaluates to 5 * 5 = 25 and hands that value back.
  5. Back in main, the call expression square(a) has produced 25. Java stores 25 in result.
  6. main prints 25 and ends.

Two important things happen here.

Parameters are like local variables for the method. They exist only during the call. When the method returns, they disappear. n does not exist back in main after step 5 — there is no way to access it from outside.

Arguments are values, not shared variables. When you wrote square(a), Java did not share the variable a with square — it passed a’s current value (5) into the parameter n. If square reassigned n inside its body, the variable a in main would not change. This rule is called pass by value for primitives, and it keeps methods from accidentally corrupting the caller’s data.

Self-check. Trace:

public static void bump(int n) {
    n = n + 1;
}
public static void main(String[] args) {
    int x = 5;
    bump(x);
    System.out.println(x);
}

What does this print?

Answer

Prints 5. Inside bump, the parameter n was a copy of the value 5. n = n + 1 changed the copy to 6, and then the method ended — n vanished, taking the modified copy with it. x in main was never touched.

Scope is the technical word for “where a variable is visible.” A parameter is visible only inside its method. A local variable declared in main is not visible inside other methods. Methods can only see what is explicitly passed to them via parameters.

That’s a feature, not a limitation. It is what lets you write and test methods in isolation: every method is a self-contained unit with a clear contract of “what I need in” and “what I give out.”

Reflection. Why can’t the caller read the parameter n from inside square(int n) after the method returns? Put differently, what would break in the language design if parameters leaked into the caller’s scope — how would testing and debugging a long program change if every method could read and write every other method’s locals?

Self-check. Can square(int n) access the variable result declared in main?

Answer

No. result is a local variable of main — out of scope inside square. For square to see any of main’s values, they have to be passed explicitly as arguments.

A beginner bug worth naming

Declaring a method does not run it. This trips students up every quarter:

public static void greet() {
    System.out.println("Hi");
}

public static void main(String[] args) {
    // never called greet() — "Hi" does not print
}

The presence of greet in the file is irrelevant. Only greet() — with the parentheses, somewhere execution actually reaches — runs the method. Defining a method is writing the recipe; calling it is cooking.


Before you leave

Methods let you reuse code and decompose a long program into named pieces. You write a header, a body, and a return if you are producing a value. You call by name, passing arguments that become parameters inside the method. Parameters are local variables that live only during the call.

This is the CS1 first-exposure version. A later unit revisits the topic and adds: passing objects (where the sharing rule changes), helper methods that call other helper methods, and designing a whole program as a set of cooperating methods.

The next lesson pairs with this one: preconditions and input validation. Methods make assumptions about their inputs. When callers violate those assumptions, a well-designed method announces the problem immediately rather than returning a nonsense answer that contaminates the rest of the program.

Want to practice parameter-passing traces? The Reges midterm parameter-mystery problems on the practice platform (filed under the Week 5 methods set) cover exactly this territory.