04 - Methods¶
What this session is¶
About 45 minutes. You'll learn how to define your own methods (Java's word for functions), use static, return values, and pass parameters. By the end you can break programs into named pieces.
"Method" vs "function"¶
Other languages call them functions. Java calls them methods because they always live inside a class. That's the only difference in vocabulary - the concept is the same: a named, reusable block of code that takes input and (usually) returns output.
The shape¶
Concrete example:
public class Math1 {
public static int doubleIt(int x) {
return x * 2;
}
public static void main(String[] args) {
System.out.println(doubleIt(5)); // 10
System.out.println(doubleIt(7)); // 14
}
}
Walk through doubleIt:
public- visible from outside the class.static- belongs to the class itself, not to any object. (We'll explainstaticproperly when we meet objects in page 05. For now: methods in amain-only program need to bestaticsomaincan call them.)int- the return type.doubleIt(int x)- name and parameter list.return x * 2;- compute and send back.
Compile and run:
Output: 10, 14.
Multiple parameters¶
Parameters are separated by commas. Each gets its own type.
Methods that return nothing¶
void means "this method returns nothing":
public static void sayHi(String name) {
System.out.println("Hi, " + name);
}
public static void main(String[] args) {
sayHi("Alice");
sayHi("Bob");
}
No return line. The method runs for its side effect (printing).
Methods calling methods¶
Methods can call other methods (including the same class's):
public class Math2 {
public static int square(int x) {
return x * x;
}
public static int sumOfSquares(int a, int b) {
return square(a) + square(b);
}
public static void main(String[] args) {
System.out.println(sumOfSquares(3, 4)); // 9 + 16 = 25
}
}
Composition - small named pieces combined.
Method overloading: multiple methods, same name, different parameters¶
Java lets you define several methods with the same name as long as their parameter lists differ:
public static int add(int a, int b) { return a + b; }
public static double add(double a, double b) { return a + b; }
public static String add(String a, String b) { return a + b; }
The compiler picks the right one based on the argument types at the call site. Useful for variants of an operation on different types.
Common overload: println itself is overloaded for every type - that's why System.out.println(42) and System.out.println("hello") both work.
Default arguments - Java doesn't have them¶
Languages like Python have default parameters: def greet(name, greeting="hello"). Java doesn't.
The Java way: overload methods.
public static String greet(String name) {
return greet(name, "hello");
}
public static String greet(String name, String greeting) {
return greeting + ", " + name;
}
One method delegates to the more-general one with a default. The IDE and the compiler give you the same affordance via overloads.
Variable scope¶
Variables created inside a method exist only inside that method:
public static int doubleIt(int x) {
int result = x * 2;
return result;
}
public static void main(String[] args) {
System.out.println(result); // ERROR - `result` doesn't exist here
}
Each method has its own world. Pass values in via parameters; get values out via return.
Local variables, parameters, and final¶
Inside a method you can mark variables final, meaning "this can't be reassigned after its first value":
public static int doubleIt(int x) {
final int multiplier = 2;
// multiplier = 3; // ERROR - can't reassign a final
return x * multiplier;
}
Useful for "this constant won't change." Increasingly, modern Java code marks variables final by default unless they need to change - the discipline forces you to think about mutation.
var for local variables (modern Java)¶
You met var in page 02 for inferred types. Same rule for locals declared from a method call:
public static void main(String[] args) {
var sum = add(3, 4); // Java infers int
var greeting = greet("Alice"); // Java infers String
System.out.println(sum);
System.out.println(greeting);
}
var for locals; explicit types for everything else.
Why methods matter¶
- Naming.
doubleIt(7)reads better than re-typing7 * 2everywhere, especially when the operation is more complex. - Reuse. Write once, call many times.
- Testing. You can test
doubleItseparately from the rest (page 10). - Structure. Reading a 500-line
mainis awful. Reading 20 small named methods tells you what the program does at a glance.
These benefits compound. They're invisible at 30 lines and decisive at 300.
Exercise¶
In a new file IsEven.java:
-
Write a method
isEven(int n)returningboolean. Use the%operator. -
From
main, printisEven(4)andisEven(7). You should seetrueandfalse. -
Write a method
countEvens(int max)returningintthat counts even numbers in1..max. Use aforloop and callisEven. -
Print
countEvens(10). Expected:5. -
Print
countEvens(100). Expected:50. -
Stretch: add overloaded
countEvens(int min, int max)that counts evens inmin..max. Test withcountEvens(5, 15)(expected:6).
What you might wonder¶
"Why static? When do I use non-static?"
static means "belongs to the class." Non-static means "belongs to an instance" (object). You'll meet instance methods in page 05. For now, in a single-file program with only main, all your helper methods are static - they have to be, so main (which is static) can call them.
"Java doesn't have first-class functions?" It does - but they're called lambdas and method references, and they were added in Java 8. We'll meet them when we need them (page 06 with collections, page 08 with pattern matching).
"What if I forget return in a non-void method?"
The compiler refuses to build. "Missing return statement." Read the error; fix the path that's missing one.
"Can a method modify its parameter?" For primitives: the parameter is a copy; modifying it doesn't affect the caller. For objects: the parameter holds a reference to the same object; modifying the object's fields does affect the caller (more in page 05).
Done¶
You can now:
- Define methods with parameters and return types.
- Use void for methods that don't return.
- Overload methods (same name, different parameters).
- Use var for inferred local types.
- Use final to mark locals as non-reassignable.
- Understand why static/non-static matters (preview).
Next page: classes and objects - where Java's everything-is-a-class design really kicks in.