Before this lesson
Understand Java primitive types, conditions and loops. This lesson introduces method parameters and array contracts.
What you will be able to do
Extract reusable computation and understand parameters and return values.
Understand the mechanism
A method signature declares parameter and return types. Extracting a sum from main lets different inputs be checked independently without copying the loop. State whether empty arrays, null and negative values are allowed.
Java always passes arguments by value. An array parameter receives a copy of a reference. Element changes affect the shared array, while reassigning the parameter does not replace the caller’s variable.
sum reads input and returns a long without mutating the array. The empty sum is defined as zero and null is explicitly rejected. These boundaries belong to the interface contract.
Runnable example
Use JDK 21. Save Main.java in a separate practice directory, compile with javac -encoding UTF-8 Main.java, then run java Main. Each lesson is independent; do not combine multiple public Main classes.
public class Main {
static long sum(int[] values) {
if (values == null) throw new IllegalArgumentException("values required");
long total = 0;
for (int value : values) total += value;
return total;
}
public static void main(String[] args) {
int[] minutes = {25, 30, 15};
System.out.println(sum(minutes));
System.out.println(sum(new int[0]));
System.out.println(minutes[0]);
}
}
Trace and verify
Output is 70, 0 and 25. The last line verifies the first element was not overwritten.
Common mistakes and boundaries
Returning long increases range but is not unlimited arithmetic. Keep printing and input handling separate from summation.
Practice challenge
Write countAtLeast(int[] values, int minimum), counting values at or above the threshold.
Reference solution and reasoning
Keep the null check, start a counter at zero, increment when value>=minimum and return it. The sample with threshold 25 gives 2; an empty array gives 0.
Lab: pass-by-value can still expose mutable arrays
Saying Java passes by reference hides an important distinction. A parameter receives a copy of a reference value. It can mutate the referenced array, but rebinding that local parameter does not rebind the caller variable. Compile this standalone Main.java with JDK 21.
import java.util.Arrays;
public class Main {
static void change(int[] values) {
values[0] = 9;
values = new int[]{100, 200};
values[1] = 300;
}
public static void main(String[] args) {
int[] original = {1, 2};
change(original);
System.out.println(Arrays.toString(original));
int[] copy = Arrays.copyOf(original, original.length);
copy[0] = 0;
System.out.println(Arrays.toString(original));
System.out.println(Arrays.toString(copy));
}
}
Expected observations
The lines are [9, 2], [9, 2] and [0, 2]. The caller never receives [100, 300].
Why this happens and where it stops applying
The first assignment mutates the shared array. The second changes only the local parameter, leaving the caller reference untouched. Copying an int[] separates its primitive elements. Copying an object array copies references, so mutable objects inside may remain shared. Document whether an API mutates its argument or returns new state rather than requiring callers to discover side effects experimentally.
Extension challenge
Design doubleValues without mutating its input. Handle empty arrays and define a null policy.
Reasoned solution
Require a non-null argument, allocate an equal-length array and fill it with Math.multiplyExact(value, 2). Empty input produces an empty array. multiplyExact rejects overflow instead of silently wrapping large values. Document both the null and overflow failure cases.