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.

Further reading