Methods: parameters, return, scope, overloading, Math and Random
Method header, parameter and argument, return and void, pass-by-value, scope, method overloading, the Math class and random number ranges. The foundation of the 'write a method' questions on the midterm.
A method is a named block of code that does one job. Instead of writing the same job in ten places, you write it once and call it from wherever you like. On the midterm it comes from two sides: “what do these calls print?” (tracing from the inside out, pass-by-value) and “write a method that does this job” (isPrime, sumDigits, max). In the second kind, writing the header correctly earns points on its own.
Golden rules:
- Header template:
public static <return type> <name>(<parameters>). - If it is not void, every path must have a return and the returned value must match the type.
- return ends the method immediately.
- Pass-by-value: a method cannot change the caller’s variable.
- Overloading = same name, different parameter list. A different return type alone is not enough.
Anatomy of a method
public static double average(int a, int b) {
return (a + b) / 2.0;
}
| Part | In this example | Meaning |
|---|---|---|
| access modifier | public | can be called from anywhere |
static | static | called directly, without creating an object (main is static too) |
| return type | double | the type of the value the method gives back; void if it gives nothing |
| name | average | starts lowercase, like a verb: computeTotal, isEven |
| parameter list | (int a, int b) | the values the method takes from outside |
| body | { return ...; } | where the work is done |
A parameter is the variable in the header: a, b. An argument is the actual value given during the call: 3 and 4 in the call average(3, 4). The number, order and type of the arguments must match the parameters.
In this course, methods are written in the same class as main and are static because they are called from main. Defining a method does not run it; it runs only when it is called.
return and void
public static int twice(int n) { return n * 2; }
public static void greet(String name) { System.out.println("Hi " + name); }
public static int max(int a, int b) {
if (a > b) return a;
return b;
}
public static void line(int n, char c) {
for (int i = 0; i < n; i++) System.out.print(c);
System.out.println();
}
// in main:
System.out.println(twice(4));
greet("Deniz");
int t = twice(twice(3)); // inside out: twice(3) = 6, twice(6) = 12
System.out.println(t);
System.out.println(average(3, 4));
System.out.println(max(8, 11) + " " + max(5, 5));
line(5, '=');
8
Hi Deniz
12
3.5
11 5
=====
- A method that returns a value is used inside an expression: it is printed, assigned to a variable, or becomes an argument to another call.
- A void method does a job (like printing) and returns nothing.
System.out.println(greet("x"))does not compile.
Return errors the compiler catches
static int f(int a) { return 2.5; } // double does not fit in int
static void g() { return 5; } // void cannot return a value
static int h(int a) { if (a > 0) return 1; } // no return when a <= 0
Ret.java:2: error: incompatible types: possible lossy conversion from double to int
Ret.java:3: error: incompatible types: unexpected return value
Miss.java:2: error: missing return statement
The missing return statement error says this: the compiler cannot know what the method will return when the condition is false. There must be a return at the end of every possible path.
Tracing calls and pass-by-value
When a method is called, Java:
- Computes the arguments.
- Copies their values into the parameters.
- Runs the method’s body.
- When it sees return, carries the value back to where the call was made.
public static void change(int x) {
x = 100;
System.out.println("inside: " + x);
}
// in main:
int a = 3;
change(a);
System.out.println("outside: " + a);
inside: 100
outside: 3
Not a itself but its value (3) went to change. x = 100 changed only the method’s own copy. This is called pass-by-value, and everything in Java is passed this way. (With arrays and objects this rule has an interesting consequence; you will see it in weeks 6 and 13.)
Scope
A variable lives only inside the block { } where it is declared.
- A variable declared inside a method (a local variable) is not visible in another method.
- Parameters are local too; they disappear when the method ends.
- A counter declared in a for header does not exist after the loop.
static void a() { int secret = 5; }
static void b() { System.out.println(secret); }
LocalScope.java:3: error: cannot find symbol
Different methods can have variables with the same name (n in main, n in counter); they are unrelated to each other.
Method overloading
A class can have several methods with the same name, as long as their parameter lists (count, type or order) differ. The combination of the method name and the parameter types is called the signature.
static int add(int a, int b) { return a + b; }
static double add(double a, double b) { return a + b; }
static int add(int a, int b, int c) { return a + b + c; }
// in main:
System.out.println(add(2, 3)); // int, int
System.out.println(add(2.0, 3)); // double, int → 3 widens → add(double, double)
System.out.println(add(1, 2, 3)); // three arguments
5
5.0
6
The selection rule: first an exact match is looked for. If there is none, Java goes to the nearest type the argument can widen to (int → long → float → double). Narrowing is never done automatically.
PITFALL · only the return type differs.
static int k(int a)andstatic double k(int b)do not compile together:method k(int) is already defined. The parameter name and the return type are not part of the signature.
The Math class
The methods of Math are static: they are called as Math.name(...), no import is needed.
System.out.println(Math.pow(3, 2));
System.out.println(Math.sqrt(16));
System.out.println(Math.max(4, 9) + " " + Math.min(4, 9));
System.out.println(Math.max(4, 9.0));
System.out.println(Math.abs(-3.5) + " " + Math.abs(-7));
System.out.println(Math.round(3.49) + " " + Math.round(3.5) + " " + Math.round(-2.5));
System.out.println(Math.ceil(2.1) + " " + Math.floor(2.9) + " " + Math.ceil(-2.1));
System.out.println(Math.PI);
9.0
4.0
9 4
9.0
3.5 7
3 4 -2
3.0 2.0 -2.0
3.141592653589793
| Method | What it does | Return type |
|---|---|---|
Math.pow(a, b) | a to the power b | always double |
Math.sqrt(x) | square root | double |
Math.abs(x) | absolute value | type of the argument |
Math.max(a, b), Math.min(a, b) | larger, smaller | type of the arguments (double if one is double) |
Math.round(x) | nearest integer, .5 rounds up | long (with a double argument) |
Math.ceil(x) | round up | double |
Math.floor(x) | round down | double |
PITFALL ·
Math.pow(2, 3)is 8.0, not 8. In output questions, remember that methods returning a double are printed with.0.
Math.round(-2.5) gives -2: the rule “.5 rounds up” means up on the number line, that is, toward the larger number.
Random numbers
There are two ways:
import java.util.Random;
Random rand = new Random();
int die = rand.nextInt(6) + 1; // 1..6
int r = rand.nextInt(11) + 10; // 10..20
int m = (int) (Math.random() * 100) + 1; // 1..100
The smallest and largest values seen when each expression is run a million times:
1..6 10..20 1..100
The formula: for min..max, rand.nextInt(max - min + 1) + min. nextInt(k) produces k different values from 0 to k-1; + min shifts the range.
Math.random() gives a double between 0.0 and 1.0 (1.0 excluded). Multiply, cast, shift. The placement of the parentheses is critical: (int) Math.random() * 100 is always 0, because the cast is done before the multiplication.
Worked example: how a writing question earns points
In a question like “write isPrime”, partial credit comes in this order:
- Header:
public static boolean isPrime(int n). If the answer is yes/no, the return type is boolean. - Special case:
if (n < 2) return false; - Loop and condition:
for (int i = 2; i * i <= n; i++) if (n % i == 0) return false; - After the loop:
return true; - Test on paper with an example: for 9, i = 2 (remainder 1), i = 3 (remainder 0) → false. Correct.
PITFALL · putting return true in an else. If you write
if (n % i == 0) return false; else return true;, the loop ends on the first iteration and you only check divisibility by 2. It says 9 is “prime”.
Common mistakes
| Wrong idea | The truth |
|---|---|
| Defining a method runs it | It runs only when called |
| The returned value is written somewhere automatically | If you do not assign or print it, it is lost |
| Changing a parameter inside a method changes main | Pass-by-value, the copy changes |
Lines after return also run | The method ends there |
return x; from a void method | Only return; is allowed |
| Two methods differing only in return type = overloading | Does not compile |
Math.sqrt(16) → 4 | 4.0 |
Math.round(2.5) → 2 | 3 |
rand.nextInt(6) for a die | It gives 0..5; add + 1 |
(int) Math.random() * 6 + 1 as a die | Always 1; write (int) (Math.random() * 6) + 1 |
| Accessing another method’s variable | A local variable lives only in its own block |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
What is printed?
static int f(int x) { return x + 3; }
static int g(int x) { return f(x) * 2; }
// in main:
System.out.println(g(4));Show answer
g(4) first calls f(4): 4 + 3 = 7. Back in g: 7 * 2 = 14. The inner call always finishes first.
What is printed?
static int mystery(int n) {
int r = 0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 1) r += i;
}
return r;
}
// in main:
System.out.println(mystery(6));Show answer
It adds the odd numbers from 1 to 6: 1 + 3 + 5 = 9.
What is printed?
static void swap(int a, int b) {
int t = a; a = b; b = t;
System.out.println("in swap: " + a + " " + b);
}
// in main:
int x = 5, y = 9;
swap(x, y);
System.out.println("in main: " + x + " " + y);Show answer
in main: 5 9
Java works by pass-by-value: copies of x and y go to the method. swap changes its own copies (it prints 9 5) but cannot touch x and y in main.
What is printed?
static int early(int n) {
if (n > 5) return 1;
System.out.println("small");
return 0;
}
// in main:
System.out.println(early(8));
System.out.println(early(2));Show answer
small
0
early(8): 8 > 5 → return 1, the method ends immediately, small is not printed. early(2): the condition is false, small is printed, then 0 is returned and main prints it.
What is printed?
static int counter(int n) {
n++;
return n;
}
// in main:
int n = 10;
n = counter(n);
counter(n);
System.out.println(n);Show answer
The result of the first call (11) is assigned to n. The second call returns 12, but since the result is not assigned anywhere, it is lost. The n in main stays 11.
What is printed?
static void show(int x) { System.out.println("int: " + x); }
static void show(double x) { System.out.println("double: " + x); }
static void show(String s) { System.out.println("String: " + s); }
// in main:
show(7 / 2);
show(7 / 2.0);
show("" + 7 / 2);Show answer
double: 3.5
String: 3
The argument is computed first, then the method is chosen by its type. 7 / 2 = 3 (int) → show(int). 7 / 2.0 = 3.5 (double) → show(double). "" + 7 / 2: division first (3), then concatenation → the String "3" → show(String).
Only these two overloads exist. What is printed?
static void p(double d) { System.out.println("double " + d); }
static void p(long l) { System.out.println("long " + l); }
// in main:
p(5);
p(5.0f);Show answer
double 5.0
There is no p(int). Java sends an int argument to the nearest type it can widen to: int → long comes before double. 5.0f is a float; it cannot go to long (narrowing), it widens to double.
What is printed?
System.out.println(Math.pow(2, 3) + Math.max(2, 3));
System.out.println(Math.sqrt(25) + " " + Math.abs(-4) + " " + Math.round(2.5));
System.out.println(Math.ceil(4.1) + " " + Math.floor(4.9) + " " + (int) Math.ceil(4.1));Show answer
5.0 4 3
5.0 4.0 5
pow always returns a double: 8.0 + 3 = 11.0. sqrt is also a double: 5.0. abs and max keep the type of the argument: 4. round(2.5) is the nearest integer, .5 rounds up: 3. ceil/floor return a double: 5.0, 4.0. Converted to int with a cast, 5.
What is printed?
static int square(int x) { return x * x; }
static int twice(int n) { return n * 2; }
static int max(int a, int b) { if (a > b) return a; return b; }
// in main:
System.out.println(square(square(2)) + square(3));
System.out.println(max(square(3), twice(5)));Show answer
10
square(2) = 4, square(4) = 16, square(3) = 9, 16 + 9 = 25. Second line: max(9, 10) = 10.
Assume Random rand = new Random();. Which values can each expression produce? (a) rand.nextInt(6) + 1 (b) rand.nextInt(5) + 3 (c) (int) (Math.random() * 10) (d) (int) Math.random() * 10
Show answer
nextInt(k) gives 0 to k-1. (a) 0..5 + 1. (b) 0..4 + 3. (c) Math.random() is 0.0 ≤ x < 1.0, × 10 → 0.0..9.99, cast → 0..9. (d) The cast applies first to Math.random(): (int) 0.73 = 0, 0 * 10 = 0. In verification the sum of 1000 trials came out 0.
Write a static method isPrime(int n) that returns true if n is prime. Numbers less than 2 are not prime.
Show answer
You look for a divisor; finding one is enough. return true must be outside the loop: it runs only if no divisor was found.public static boolean isPrime(int n) { if (n < 2) return false; for (int i = 2; i * i <= n; i++) { if (n % i == 0) return false; } return true;}Primes from 1..30: 2 3 5 7 11 13 17 19 23 29. isPrime(49) → false, isPrime(97) → true. Writing i < n instead of i * i <= n is also correct, just slower.
Write a static method sumDigits(int n) that returns the sum of the digits of a non-negative integer, using a while loop. Example: sumDigits(4823) returns 17.
Show answer
% 10 gives the last digit, / 10 removes it. When n becomes 0 there are no digits left.public static int sumDigits(int n) { int sum = 0; while (n > 0) { sum += n % 10; n /= 10; } return sum;}Test: 4823 → 17, 309 → 12, 7 → 7, 0 → 0 (the loop is never entered).
Verification: All outputs were run with JDK 26 (verify/SEN1001/W05.java). The Random ranges were observed over 1,000,000 trials (min..max). The compile errors were obtained by compiling verify/SEN1001/err/Ret.java, Miss.java and LocalScope.java with javac.