Methods & Arrays: Reusable Code and Collections of Data
As programs grow, two problems appear. First, you find yourself copying the same lines again and again—methods solve that by letting you name a block of code and reuse it. Second, you need to handle many values at once, not just single variables—arrays solve that by storing a fixed-size collection under one name. Together these are the workhorses of real code. In a test framework, a method might be “log in with this username and password”, called from a hundred tests; an array might hold every expected product name you need to verify. This module builds both skills from scratch with testing-flavoured examples.
Learning objectives
By the end of this lesson you will be able to:
- Define methods with parameters and return types, and call them.
- Use method overloading to give one name several forms.
- Explain variable scope and the difference between
staticand instance methods (briefly). - Write methods that accept a variable number of arguments with varargs.
- Declare, initialise, index, and iterate over one-dimensional arrays.
- Work with two-dimensional arrays for grids and tables.
- Use the
Arraysutility class for common tasks like sorting and printing.
What is a method?
A method is a named block of code that performs a task. You have already used methods—System.out.println is one—and you have written one: main. Now you will write your own. Defining a method means you can run that code any time by calling its name, instead of retyping it. This is the DRY principle: Don’t Repeat Yourself. Here is the anatomy:
public static void greet() {
System.out.println("Welcome to QALaunch!");
}
public— an access modifier (who can call it); more on this in Module 4.static— means the method belongs to the class itself, so you can call it without creating an object (covered below).void— the return type.voidmeans “returns nothing”.greet— the method name, followed by()for its parameters (here, none).
You call it simply by writing its name:
public static void main(String[] args) {
greet(); // prints: Welcome to QALaunch!
greet(); // call it as many times as you like
}
Parameters and return types
Methods become powerful when they accept parameters (inputs) and produce a return value (output). Parameters are declared in the parentheses; the return type replaces void and you hand back a value with the return keyword.
// Takes two int inputs, returns their sum as an int
public static int add(int a, int b) {
return a + b;
}
// Takes a name, returns a greeting String
public static String buildGreeting(String name) {
return "Hello, " + name + "!";
}
public static void main(String[] args) {
int sum = add(3, 4); // sum is now 7
String msg = buildGreeting("Priya"); // msg is "Hello, Priya!"
System.out.println(sum);
System.out.println(msg);
}
The values you pass in (3, 4, "Priya") are called arguments. They are matched to the parameters by position and must match the declared types. Once a method returns a value, you can store it, print it, or pass it straight into another method—exactly how a test helper like getPageTitle() would feed its result into an assertion.
A method is a kitchen recipe
Think of a method as a recipe card. The name is the dish (“make an omelette”). The parameters are the ingredients you must supply (eggs, salt). The body is the steps. The return value is the finished dish handed back to you. Once the recipe is written, anyone can follow it without knowing the details—they just supply ingredients and receive the result. That is abstraction: the caller of login(user, pass) does not care how login works internally, only that it does the job. Good test frameworks are built from dozens of small, well-named recipes like this, which is what makes them readable.
Method overloading
Java lets you define several methods with the same name as long as their parameter lists differ—different number of parameters, or different types. This is overloading. Java picks the right one based on the arguments you pass.
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b, int c) { // three ints
return a + b + c;
}
public static double add(double a, double b) { // two doubles
return a + b;
}
// Java chooses the matching version automatically:
add(2, 3); // calls the first -> 5
add(2, 3, 4); // calls the second -> 9
add(2.5, 3.5); // calls the third -> 6.0
Overloading is why System.out.println happily accepts a String, an int, or a boolean—there are many overloaded versions behind that one name. Note: the return type alone cannot distinguish overloads; the parameters must differ.
Variable scope
Scope is the region of code where a variable exists and can be used. A variable declared inside a method (or a loop, or an if block) is a local variable—it lives only within the braces where it was declared and vanishes when that block ends.
public static void demo() {
int x = 10; // x exists only inside demo()
if (x > 5) {
int y = 20; // y exists only inside this if-block
System.out.println(x + y);
}
// System.out.println(y); // ERROR: y is out of scope here
}
// System.out.println(x); // ERROR: x is out of scope here too
Keeping variables in the smallest scope that works is good practice: it prevents accidental reuse and makes code easier to reason about. If two methods each declare their own x, they are completely separate—no interference.
Static vs instance methods (a first look)
You have seen static on every method so far. Here is the short version, to be expanded in Module 4. A static method belongs to the class and is called on the class name, with no object needed: Math.max(3, 7). An instance method belongs to an object (an individual thing created from a class) and is called on that object: myString.toUpperCase()—you need an actual String object to call it on.
// static: called on the class, no object required
int bigger = Math.max(3, 7); // 7
// instance: called on an object
String name = "priya";
String upper = name.toUpperCase(); // "PRIYA" - needs the object 'name'
Rule of thumb for now: utility helpers that just take inputs and return a result are often static; behaviour tied to a specific object’s data is an instance method. Module 4 makes this concrete.
Varargs: a variable number of arguments
Sometimes you want a method to accept any number of arguments. Varargs (variable arguments), written with ..., let you do that. Inside the method, the arguments arrive as an array.
public static int sumAll(int... numbers) { // accepts zero or more ints
int total = 0;
for (int n : numbers) { // numbers behaves like an array
total += n;
}
return total;
}
sumAll(); // 0
sumAll(5); // 5
sumAll(1, 2, 3, 4); // 10
A varargs parameter must be the last parameter in the list. You will see this pattern in testing utilities—for example a method that takes any number of expected values to check against.
Arrays: storing many values
An array is a fixed-size, ordered collection of values of the same type, stored under one name. Instead of test1, test2, test3, you keep one array scores. Each slot has a numbered position called an index, and—crucially—indexes start at 0. An array of 5 elements has indexes 0, 1, 2, 3, 4.
// Declare and initialise with known values:
int[] scores = {90, 85, 72, 95, 60};
// Access by index:
System.out.println(scores[0]); // 90 (the first element)
System.out.println(scores[4]); // 60 (the last element)
// Change an element:
scores[2] = 78; // the third slot is now 78
// How many elements? Use .length (a field, not a method)
System.out.println(scores.length); // 5
You can also create an empty array of a given size and fill it later. Numeric arrays default to 0, booleans to false, and object arrays (like String[]) to null.
String[] browsers = new String[3]; // three empty slots (all null)
browsers[0] = "chrome";
browsers[1] = "firefox";
browsers[2] = "edge";
The off-by-one and out-of-bounds traps
- Indexes start at 0. The last valid index is
length - 1, notlength. For a 5-element array the last index is 4. - ArrayIndexOutOfBoundsException. Accessing
scores[5]on a 5-element array throws this at runtime—a very common crash. It usually means a loop condition used<=instead of<. - Arrays are fixed size. Once created, an array cannot grow or shrink. If you need a resizable collection, you will use
ArrayList(a later module). Beginners often reach for arrays when a list is the right tool. .lengthis a field for arrays (no parentheses), but.length()is a method for Strings. Mixing them up is a frequent slip.
Iterating over arrays
To process every element, you loop. There are two idiomatic ways. The classic for loop uses the index—use it when you need the position number:
int[] scores = {90, 85, 72, 95, 60};
for (int i = 0; i < scores.length; i++) {
System.out.println("Score at index " + i + " is " + scores[i]);
}
The enhanced for loop (also called for-each) reads each element directly and is cleaner when you do not need the index:
for (int score : scores) { // read as "for each score in scores"
System.out.println(score);
}
In Selenium you will write for (WebElement row : rows) constantly—this is that exact pattern, looping over every element the browser found.
Common array tasks
A few patterns come up again and again: summing, finding a maximum, and searching.
int[] scores = {90, 85, 72, 95, 60};
int total = 0;
int max = scores[0];
boolean found95 = false;
for (int score : scores) {
total += score; // running sum
if (score > max) max = score; // track the largest
if (score == 95) found95 = true; // search
}
double average = (double) total / scores.length; // cast to avoid integer division
System.out.println("Total: " + total); // 402
System.out.println("Max: " + max); // 95
System.out.println("Average: " + average); // 80.4
System.out.println("Has a 95: " + found95); // true
Note the cast to double when computing the average—without it, 402 / 5 would use integer division and give 80, losing the .4.
Two-dimensional arrays
A 2D array is an array of arrays—a grid with rows and columns. It is perfect for tables, which you meet constantly in web testing. You index with two numbers: grid[row][column].
// A 3-row, 2-column grid of test data (username, password pairs)
String[][] credentials = {
{"alice", "pass1"},
{"bob", "pass2"},
{"carol", "pass3"}
};
System.out.println(credentials[0][0]); // "alice"
System.out.println(credentials[2][1]); // "pass3"
// Iterate over every cell with nested loops:
for (int row = 0; row < credentials.length; row++) {
for (int col = 0; col < credentials[row].length; col++) {
System.out.print(credentials[row][col] + " ");
}
System.out.println(); // new line after each row
}
That credentials grid is a sneak peek at data-driven testing: one test body, many rows of input—exactly how you would run the same login test against several accounts.
The Arrays utility class
Java ships a helper class, java.util.Arrays, full of static methods for common array work. Import it with import java.util.Arrays; and you get sorting, searching, printing, and comparing for free.
import java.util.Arrays;
int[] scores = {90, 85, 72, 95, 60};
// Print an array readably (plain println on an array prints gibberish):
System.out.println(Arrays.toString(scores)); // [90, 85, 72, 95, 60]
// Sort in place (ascending):
Arrays.sort(scores);
System.out.println(Arrays.toString(scores)); // [60, 72, 85, 90, 95]
// Fill every slot with a value:
int[] zeros = new int[3];
Arrays.fill(zeros, 7);
System.out.println(Arrays.toString(zeros)); // [7, 7, 7]
// Compare two arrays for equal contents:
System.out.println(Arrays.equals(new int[]{1,2}, new int[]{1,2})); // true
Tutor tip: never println an array directly
If you write System.out.println(scores) on an array, you get something like [I@1b6d3586—not the contents, but a cryptic internal reference. This baffles beginners every time. The fix is Arrays.toString(scores) for a 1D array, or Arrays.deepToString(grid) for a 2D array. Burn this into memory now: it will save you from staring at [Ljava.lang.String;@... wondering what went wrong. When you later debug a Selenium test that collected a list of elements, the same habit—printing contents, not references—helps you see what the browser actually found.
Hands-on exercise
Create a class MethodsAndArrays and complete each task:
- Write a
staticmethodisEven(int n)that returns aboolean, and call it from a loop over 1–10, printing each number and whether it is even. - Write an overloaded method
describe: one version takes anint, another takes aString. Print a sentence appropriate to each type, then call both. - Write a varargs method
average(double... values)that returns the mean, and test it with different numbers of arguments. - Create an
int[]of at least six numbers. Write a methodfindMax(int[] numbers)that returns the largest, and a method that returns the sum. Print both results. - Build a
String[][]of three username/password pairs. Loop over it with nested loops and print each pair on its own line. - Use
Arrays.sortandArrays.toStringto sort and print your number array. Stretch: compute and print the average as adouble, remembering the cast.
Knowledge check
- What are the parameters and the return type of a method, and what does
voidmean? - What makes two methods valid overloads of each other? Can return type alone distinguish them?
- What is variable scope, and where does a variable declared inside a loop live?
- In one line, what is the difference between a
staticmethod and an instance method? - What are varargs, and where must a varargs parameter appear in the parameter list?
- What is the index of the first element of an array, and of the last element in an array of length 5?
- Why does
System.out.println(myArray)print gibberish, and what should you use instead? - When would you choose a 2D array, and how do you access the element at row 1, column 0?
Show answers
- Parameters are the inputs declared in parentheses; the return type is the kind of value handed back with
return.voidmeans the method returns nothing. - Their parameter lists must differ in number or type. No—return type alone cannot distinguish overloads.
- Scope is the region where a variable exists; a variable declared inside a loop (or block) exists only within that block’s braces.
- A
staticmethod is called on the class with no object; an instance method is called on a specific object. - Varargs (
type... name) let a method accept any number of arguments, received as an array; the varargs parameter must be last. - The first element is index
0; the last element of a length-5 array is index4(i.e.length - 1). - It prints an internal reference, not the contents; use
Arrays.toString(myArray)(orArrays.deepToStringfor 2D). - Choose a 2D array for grids/tables of data; access row 1, column 0 with
grid[1][0].
Key takeaways
- Methods name and reuse a block of code; they take parameters and may return a value—the core of DRY, readable code.
- Overloading gives one name multiple parameter forms; the return type alone cannot distinguish them.
- Variables live only within their scope;
staticmethods belong to the class, instance methods to objects. - Varargs accept any number of arguments (as an array) and must be the last parameter.
- Arrays are fixed-size, same-type collections indexed from 0; iterate with a classic or enhanced
for; use 2D arrays for tables. - The
Arraysclass providessort,fill,equals, andtoString—neverprintlnan array directly.
Go deeper
A handful of deeper points about methods and arrays separate confident coders from those who get mysterious bugs.
Java is always pass-by-value—but a reference is a value too. When you pass an int to a method, it receives a copy; changing it inside does not touch the original. When you pass an array, the copy is a copy of the reference, so both names point at the same array—changes to its elements are visible to the caller. This surprises many beginners:
static void bump(int[] data) {
data[0] = 99; // affects the caller's array
}
int[] nums = {1, 2, 3};
bump(nums);
System.out.println(nums[0]); // 99, not 1
- Jagged arrays. A 2D array’s rows need not be the same length: write
int[][] rows = new int[3][];and give each row its own size later. Always loop withrows[i].lengthper row rather than assuming a fixed width. - More
Arrayshelpers. BeyondsortandtoString,Arrays.copyOfgrows or trims an array into a new one, andArrays.binarySearchfinds a value quickly—but only on an array that is already sorted. - Recursion. A method may call itself. Every recursive method needs a base case that stops the calls; miss it and you get a
StackOverflowError—the method equivalent of an infinite loop.