Kestrel Exams kestrel logo KESTREL EXAMSPRACTICE TO PASS
Java19 min readCode verified

Arrays: creating, passing, and the oversized array

An array is a row of numbered boxes that all hold the same type. This guide covers making one, reading and looping through it, why handing an array to a method lets the method change it, and the oversized array with a separate count, which is how you add, find and remove items in a structure that cannot grow. Every listing was compiled and run on OpenJDK 21.

Practice this topic in the free app →All Java guides

A waitlist with numbered lines#

Picture the clipboard at the host stand of a busy diner. The sheet has six printed lines. Every line holds the same kind of thing, one waiting party, and the host can point at any line by its number. You cannot add a seventh line to a printed sheet.

A Java array is that sheet. Each line is called an element, and its number is its index. This whole guide builds one small program, Waitlist, for that diner. Each section adds one idea to it, and each step shows the real output.

Trap check: where does counting start?

Every index starts at 0. A sheet of 6 lines has indexes 0 to 5, so the sixth line is index 5, not 6.

Declaring, creating and filling#

You already know how to make one variable: the type, then the name, as in int partySize;. An array uses the same shape with one change: square brackets after the type. int[] party; reads as “party is an array of ints”.

Making a usable array takes three steps. Learn them one at a time first; the short form comes after.

StepCodeWhat it does
1. Declareint[] party;makes a variable that can point at an array of ints. No array exists yet.
2. Createparty = new int[6];makes room for 6 ints and points the variable at it. The 6 is the count, not the last index.
3. Initializeparty[0] = 4;fills one element with a value, using square brackets and an index. This is called initializing it.
Try it first

Before you run it: a brand-new sheet has no names on it yet. What do you think Java puts in each element of new int[6]? And in each element of new String[6]?

Show the answer

Zeros in the int array, and null in the String array. Java never leaves an element random; it fills every one with a default value. Run the program below to check.

Waitlist.java
import java.util.Arrays;

public class Waitlist {
    public static void main(String[] args) {
        int[] party;                  // declare: a variable for an array of ints
        party = new int[6];           // create: six lines, numbered 0 to 5
        String[] names = new String[6];
        System.out.println(Arrays.toString(party));
        System.out.println(Arrays.toString(names));

        party[0] = 4;                 // fill: line 0 gets a party of 4
        names[0] = "Ortiz";
        System.out.println(Arrays.toString(party));
        System.out.println(Arrays.toString(names));
    }
}
[0, 0, 0, 0, 0, 0]
[null, null, null, null, null, null]
[4, 0, 0, 0, 0, 0]
[Ortiz, null, null, null, null, null]

Numbers start at 0 (or 0.0), booleans at false, and anything that is an object, including String, starts as null, which means “points at nothing yet”. Arrays.toString (from java.util.Arrays) turns a whole array into one String inside square brackets, and println prints that String.

Now the short forms. Steps 1 and 2 fit on one line: int[] party = new int[6];. And if you already know the values, an initializer list does all three steps at once and counts the elements for you: int[] party = {4, 2, 5, 3};. The curly-brace form only works on the line that declares the variable. Anywhere else, write party = new int[] {4, 2, 5, 3};.

length, and stepping off the end#

Every array knows its size through length. It is a field, a value stored with the array, not a method, so it takes no parentheses: party.length. A String uses the method s.length(), with parentheses, and an ArrayList uses size(). Mixing these up is a classic compile error.

The program now starts from four waiting parties:

Waitlist.java
public class Waitlist {
    public static void main(String[] args) {
        int[] party = {4, 2, 5, 3};
        System.out.println(party.length);
        System.out.println(party[0]);
        System.out.println(party[party.length - 1]);
        System.out.println(party[4]);
    }
}
4
4
3
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4
	at Waitlist.main(Waitlist.java:7)

The valid indexes run from 0 to length - 1, so the last party is party[party.length - 1]. Asking for index 4 in an array of length 4 compiles fine, then stops the program with ArrayIndexOutOfBoundsException. Read the message: it gives you both numbers, the index you asked for and the length you had.

Looping through every element#

The host wants two numbers: how many guests are waiting in total, and the average party size.

Try it first

The parties are 4, 2, 5 and 3. Work out the total and the average yourself before you read the code.

Show the answer

The total is 14 and the average is 3.5. Keep that 3.5 in mind for the next output.

Waitlist.java
public class Waitlist {
    public static void main(String[] args) {
        int[] party = {4, 2, 5, 3};

        int total = 0;                // the accumulator starts at 0
        for (int guests : party) {
            total += guests;          // and grows by one value per pass
        }
        System.out.println("Guests waiting: " + total);
        System.out.println("Average party: " + total / party.length);
    }
}
Guests waiting: 14
Average party: 3

The total is right. The running total in total is called the accumulator pattern: start a variable at 0 before the loop, add one value to it on every pass, and read it after the loop ends.

The average is not right. Does 3 make sense? You predicted 3.5. The answer has to sit between the smallest party (2) and the largest (5), so 3 is possible. That is exactly why a wrong answer like this slips through when nobody predicted first. The same check matters when a tool or an AI hands you an answer: decide roughly what it should be, then compare.

Trap check: integer or floating-point division?

Every time you divide, stop and ask what type each side is. total is an int and party.length is an int, so 14 / 4 is integer division and throws away the .5. Make one side a double first with a cast, which converts a value to another type: (double) total / party.length.

With that one change to the last line:

Guests waiting: 14
Average party: 3.5

The loop above is the for-each loop: for (int guests : party) reads as “for each int guests in party”. It is the short way when you only need each value. When you need to know where a value is, use the counting for loop. It has four parts: the initialization (int i = 1), the condition (i < party.length), the update (i++) and the body inside the curly braces.

Waitlist.java
public class Waitlist {
    public static void main(String[] args) {
        int[] party = {4, 2, 5, 3};

        int biggest = 0;              // index of the biggest party so far
        for (int i = 1; i < party.length; i++) {
            if (party[i] > party[biggest]) {
                biggest = i;
            }
        }
        System.out.println("Biggest: " + party[biggest] + " on line " + biggest);

        for (int guests : party) {
            guests = 0;               // changes the copy, not the array
        }
        System.out.println("Line 0 still holds " + party[0]);
    }
}
Biggest: 5 on line 2
Line 0 still holds 4

The search assumes line 0 is the biggest (biggest holds an index) and lets the loop prove otherwise from index 1. Starting with a biggest value of 0 instead would give a wrong answer if every value were negative. The second loop shows the for-each limit: guests is a copy of each value, so setting it to 0 changes the copy and leaves the array alone. To change elements, use a counting loop and write party[i] = ....

Shrink it to the smallest case. To check a loop condition, shrink the array until you can trace it in your head. With one party, {4}, the loop for (int i = 0; i < party.length; i++) runs with i = 0, then tests 1 < 1, which is false, so it runs exactly once. Written with i <= party.length, it would run a second time with i = 1 and throw. One element is small enough to be sure.

A convention worth adopting: write i < party.length rather than i <= party.length - 1. Both are correct, but the first shows the count directly and has one less piece to get wrong. If you prefer the second, it is not a mistake.

Arrays are stored as references#

An array variable does not hold the elements. It holds a reference: an arrow pointing to where the elements live. At the diner, the host stand and the kitchen screen show the same list. Change it on one and the other shows the change, because there is only one list.

Waitlist.java
import java.util.Arrays;

public class Waitlist {
    public static void main(String[] args) {
        int[] party = {4, 2, 5, 3};
        int[] kitchenView = party;    // a second arrow to the same list
        kitchenView[1] = 3;           // the party on line 1 grew by one
        System.out.println(Arrays.toString(party));

        int[] snapshot = Arrays.copyOf(party, party.length);
        snapshot[0] = 9;
        System.out.println(Arrays.toString(party));
        System.out.println(Arrays.toString(snapshot));

        int[] same = {4, 3, 5, 3};
        System.out.println(party == same);
        System.out.println(Arrays.equals(party, same));

        System.out.println(party);
    }
}
[4, 3, 5, 3]
[4, 3, 5, 3]
[9, 3, 5, 3]
false
true
[I@659e0bfd

kitchenView = party copied the arrow, not the list, so changing kitchenView[1] changed what party sees. Arrays.copyOf makes a real second list, so changing snapshot left party alone. For comparing, == asks “same list?” and Arrays.equals asks “same values in the same order?”.

The last line is shown on purpose, because you will meet it. Printing the array variable itself does not print the values. [I@659e0bfd is the array’s type and a hash code: [ means “array”, I means int, and the part after @ is a number Java uses to identify the object. It will be different when you run it. Seeing it means “you printed the reference”; use Arrays.toString to see the contents.

Passing an array to a method, and returning one#

Java passes every argument as a copy of its value, which is called pass-by-value. For an array, the value is the arrow. So a method can change the elements of the caller’s array, but pointing its own copy at a new array does nothing for the caller.

Try it first

In the program below, clearBoard sets its parameter to a brand-new empty array. After the call, is the caller’s waitlist empty?

Show the answer

No. The method moved its own copy of the arrow to a new array. The caller’s arrow still points at the original list, so it prints [4, 2, 5, 4] again.

Waitlist.java
import java.util.Arrays;

public class Waitlist {
    public static void addGuests(int[] party, int line, int extra) {
        party[line] += extra;
    }

    public static void clearBoard(int[] party) {
        party = new int[6];
    }

    public static int[] bigParties(int[] party, int min) {
        int count = 0;
        for (int guests : party) {
            if (guests >= min) {
                count++;
            }
        }
        int[] result = new int[count];
        int next = 0;
        for (int guests : party) {
            if (guests >= min) {
                result[next] = guests;
                next++;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[] party = {4, 2, 5, 3};
        addGuests(party, 3, 1);
        System.out.println(Arrays.toString(party));
        clearBoard(party);
        System.out.println(Arrays.toString(party));
        System.out.println(Arrays.toString(bigParties(party, 4)));
    }
}
[4, 2, 5, 4]
[4, 2, 5, 4]
[4, 5, 4]

addGuests changed an element, and the change stuck. clearBoard changed nothing the caller can see. bigParties shows how to hand back a new array: build it inside, then return it. The return type int[] says the method returns an array of ints. It works in two passes, one to count how big the result must be and one to fill it, because an array’s size is fixed once it is created.

Notice that nothing inside bigParties is really about diners. Give it the seat counts of a bus, the scores of a game or the page counts of a book, and it still returns the values at or above min. One method, written once, works for any array of that type. That is why, outside a themed example like this one, array parameters usually get general names such as values or nums; party here is only for the story.

The array you have typed since your first program#

Every program you have written starts with public static void main(String[] args). You can now read the last part: args is an array of Strings. When you run a program from a terminal, any words you type after the class name are placed in it, one per element.

Waitlist.java
public class Waitlist {
    public static void main(String[] args) {
        System.out.println("Arguments: " + args.length);
        if (args.length > 0) {
            int first = Integer.parseInt(args[0]);
            System.out.println("First party: " + first + " guests");
            System.out.println("As text, doubled: " + args[0] + args[0]);
            System.out.println("As a number, doubled: " + (first + first));
        }
    }
}

Run with two arguments, then with none:

$ java Waitlist 4 2
Arguments: 2
First party: 4 guests
As text, doubled: 44
As a number, doubled: 8

$ java Waitlist
Arguments: 0

args[0] is the String "4", not the number 4, even though you typed a digit. That is why “doubling” it as text joined it to itself and gave 44. Integer.parseInt turns the text into an int. With no arguments, args.length is 0, which is why the program checks it before touching args[0]. An editor’s Run button usually runs main with an empty array, so the check matters there too.

Perfect-size and oversized arrays#

An array cannot grow, so there are two ways to use one:

  • A perfect-size array has exactly as many elements as there are items, so length is the item count. It suits data whose count you know up front.
  • An oversized array is made bigger than you need, and a separate int, usually called size or count, remembers how many elements are in use. It suits items that come and go.

The diner’s clipboard is the oversized kind: 6 printed lines, but only some are filled at any moment. The parties in use are always packed at the front, in indexes 0 to size - 1, and everything after that is spare. This is the oversized array with a count pattern, and its one rule is: every loop stops at size, not at length.

Adding, finding and removing in an oversized array#

Here is the waitlist as a list of names, with the three operations written as methods that share the array and its count. Read them as a set.

Try it first

The list holds Ortiz, Lee, Patel and Nguyen. Lee is seated, so remove("Lee") runs. Write down the list and the new size before you look at the output.

Show the answer

Ortiz, Patel, Nguyen, with size 3. Patel and Nguyen each slid up one line to close the gap.

Waitlist.java
public class Waitlist {
    static String[] names = new String[6];    // the clipboard: 6 lines
    static int size = 0;                      // how many lines are in use

    static boolean add(String name) {
        if (size == names.length) {
            return false;                     // clipboard full
        }
        names[size] = name;                   // first empty line
        size++;
        return true;
    }

    static int find(String name) {
        for (int i = 0; i < size; i++) {      // stop at size, not length
            if (names[i].equals(name)) {
                return i;
            }
        }
        return -1;                            // not on the list
    }

    static boolean remove(String name) {
        int at = find(name);
        if (at == -1) {
            return false;
        }
        for (int i = at; i < size - 1; i++) {
            names[i] = names[i + 1];          // slide each later name up
        }
        size--;
        return true;
    }

    static void show() {
        String line = "size " + size + ":";
        for (int i = 0; i < size; i++) {
            line += " " + names[i];
        }
        System.out.println(line);
    }

    public static void main(String[] args) {
        add("Ortiz");
        add("Lee");
        add("Patel");
        add("Nguyen");
        show();
        System.out.println("Lee is on line " + find("Lee"));
        System.out.println("Kim is on line " + find("Kim"));
        remove("Lee");
        show();
        add("Kim");
        add("Adams");
        add("Brooks");
        show();
        System.out.println("Room for Cho? " + add("Cho"));
    }
}
size 4: Ortiz Lee Patel Nguyen
Lee is on line 1
Kim is on line -1
size 3: Ortiz Patel Nguyen
size 6: Ortiz Patel Nguyen Kim Adams Brooks
Room for Cho? false
  • Add: put the new name at index size (the first empty line), then add 1 to size. Check first that there is an empty line.
  • Find: walk indexes 0 to size - 1 and return the index of the first match, or -1 if there is none. This is a linear search. Strings are compared with equals, not ==.
  • Remove: find the name, slide every later name up one line to close the gap, then subtract 1 from size. The old copy left at the end is now in the spare area, so it no longer counts.
Trap check: < size or < size - 1?

The remove loop stops at size - 1 because it reads names[i + 1]. Shrink it to check: with one name on the list and remove called on it, at is 0 and the loop condition 0 < 0 is false, so it runs zero times and size becomes 0. Written as i < size, the last pass would read one line past the names in use, and on a full clipboard that is names[6], which throws ArrayIndexOutOfBoundsException.

If the order does not matter, there is a faster remove: copy the last name into the gap and subtract 1 from size. One move instead of many. The ArrayList guide shows a class that does all of this bookkeeping for you.

Type this one yourself

Do not paste it. Add a method insertAt(int index, String name) to the program that puts a late reservation on a given line and moves everyone below it down one line. Typing it is how the loop direction sticks. A valid line is 0 to size; refuse anything else. Test it with Ortiz, Patel and Nguyen on the list: insert Kim at line 0, then Lee at line 2.

Show the answer

Slide from the back, or each move overwrites the name you need next:

static boolean insertAt(int index, String name) {
    if (size == names.length || index < 0 || index > size) {
        return false;
    }
    for (int i = size; i > index; i--) {
        names[i] = names[i - 1];          // move from the back first
    }
    names[index] = name;
    size++;
    return true;
}
size 4: Kim Ortiz Patel Nguyen
size 5: Kim Ortiz Lee Patel Nguyen

What was new in this guide#

  1. The data type int[]: the type you know, plus square brackets.
  2. new int[6] to make room for 6 elements, all set to a default value.
  3. party[i] to read or write one element, with indexes from 0 to length - 1.
  4. length, a field with no parentheses, and the loops that use it: for-each for values, counting for for positions.
  5. Arrays are references, so copying or passing the variable shares the array; a method can also build a new array and return it.
  6. Initializer lists like {4, 2, 5, 3}, plus Arrays.toString, Arrays.copyOf and Arrays.equals.
  7. String[] args is an ordinary array of Strings.
  8. Perfect-size versus oversized arrays, and how to add, find and remove in an oversized one.
One sentence to carry into the exam

An array is a fixed row of elements numbered 0 to length - 1, and the variable holds an arrow to it, not the elements themselves. Copying or passing the variable shares the elements; an oversized array needs its own size counter, and every loop stops there.

Where these go wrong#

  • party.length() with parentheses. For arrays it is length, a field. Strings use length().
  • Looping with i <= party.length. The last valid index is length - 1; this throws ArrayIndexOutOfBoundsException.
  • Dividing two ints for an average. 14 / 4 is 3. Cast one side to double first.
  • Thinking int[] b = a; copies the array. It copies the reference. Use Arrays.copyOf or a loop.
  • Comparing arrays with == or printing them directly. Use Arrays.equals and Arrays.toString.
  • Changing elements through a for-each variable. It is a copy of the value. Use a counting loop to change elements.
  • Looping an oversized array to length. Stop at size; the rest are spare, often null, and calling equals on null throws a NullPointerException.
  • Forgetting size++ or size--. The data looks right and the count is wrong, so the next add or loop misbehaves.
  • Using {4, 2, 5, 3} after the declaration line. Write party = new int[] {4, 2, 5, 3}; instead.
  • Treating args[0] as a number. It is a String. Convert it with Integer.parseInt, and check args.length first.

On the exam: if a question says “write a method”, write only the method: its header, its body and its return. If it says “write a program”, include the class and main. Read the question, read it again, answer it, then read it once more to check you did every part.

Practice#

Answer each one on paper before you look at the solutions. Every answer that involves running code was checked by compiling and running it.

  1. After double[] p = new double[3]; and String[] s = new String[2];, what is in each array?
  2. Write a method countAbove(int[] nums, int limit) that returns how many elements are greater than limit.
  3. What prints?
    int[] x = {4, 5, 6};
    int[] y = x;
    y[2] = 0;
    x = new int[] {7, 8};
    System.out.println(Arrays.toString(x));
    System.out.println(Arrays.toString(y));
  4. Write a method that takes an int[] and returns a new array with the elements in reverse order, leaving the original unchanged.
  5. An oversized array names has length 10 and size is 4. What are the valid indexes of items in use, and what two lines add "Zoe"?
  6. In an oversized array holding [A, B, C, D] with size 4, list the moves the order-keeping remove makes to delete B, and give the new size.

Solutions#

  1. p holds [0.0, 0.0, 0.0] and s holds [null, null]. new fills numbers with zero, booleans with false, and object types with null.
  2. A for-each loop is enough, because only the values are needed:
    public class QSum {
        public static int countAbove(int[] nums, int limit) {
            int count = 0;
            for (int n : nums) {
                if (n > limit) {
                    count++;
                }
            }
            return count;
        }
    
        public static void main(String[] args) {
            int[] temps = {71, 88, 93, 64, 90};
            System.out.println(countAbove(temps, 85));
        }
    }
    3
  3. y = x shares the first array, so y[2] = 0 changes it. Then x is pointed at a new array, and y still points at the old one:
    import java.util.Arrays;
    
    public class QTrace {
        public static void main(String[] args) {
            int[] x = {4, 5, 6};
            int[] y = x;
            y[2] = 0;
            x = new int[] {7, 8};
            System.out.println(Arrays.toString(x));
            System.out.println(Arrays.toString(y));
        }
    }
    [7, 8]
    [4, 5, 0]
  4. Create a new array of the same length and fill it from the back of the original:
    import java.util.Arrays;
    
    public class QReverse {
        public static int[] reversed(int[] a) {
            int[] r = new int[a.length];
            for (int i = 0; i < a.length; i++) {
                r[i] = a[a.length - 1 - i];
            }
            return r;
        }
    
        public static void main(String[] args) {
            int[] a = {1, 2, 3, 4};
            System.out.println(Arrays.toString(reversed(a)));
            System.out.println(Arrays.toString(a));
        }
    }
    [4, 3, 2, 1]
    [1, 2, 3, 4]
  5. Indexes 0 to 3. To add: names[size] = "Zoe"; then size++;, after first checking that size < names.length.
  6. B is at index 1. Slide left: index 1 gets C, index 2 gets D. Then size becomes 3, so the items in use are [A, C, D]. The old D still sitting at index 3 is now in the spare area and is ignored.

Test-readiness checklist#

These are the items from the course’s Exam 2 topic list that this guide covers. Tick each one only when you can do it without looking.

  • ☐  I can declare an array, create space for it using new, and initialize it, including with an initializer list.
  • ☐  I can pass an array to a method and return an array from a method, and predict what the caller sees.
  • ☐  I can explain perfect-sized and oversized arrays, and why arrays are stored as references.
  • ☐  I can iterate through all elements with a counting loop and a for-each loop.
  • ☐  I can find an element, remove an element and add an element in an oversized array.

Test yourself in the free Kestrel Exams app

40 practice questions on declaring, passing and oversized arrays, with every code answer checked by compiling and running it. Free, offline, no account.

Practise arrays →

Frequently asked questions#

How do you declare and create an array in Java?

Declare the variable with brackets after the type, such as int[] scores;. Create the space with new and a size, such as scores = new int[5];. Or do both and fill it at once with an initializer list: int[] scores = {90, 85, 77};.

What are the default values in a new Java array?

Numeric elements start at 0 (or 0.0), boolean elements at false, char elements at the null character, and elements of any object type, including String, at null.

Is it length or length() for an array?

length, with no parentheses. It is a field of every array. Strings use the method length() with parentheses, and ArrayLists use size().

What causes ArrayIndexOutOfBoundsException?

Using an index below 0 or at or above the array's length. The valid indexes run from 0 to length - 1. The usual cause is a loop condition written as i <= array.length instead of i < array.length.

Why does changing an array inside a method change it for the caller?

Because an array variable holds a reference to the array. The method receives a copy of that reference, which points at the same array, so changes to its elements are visible to the caller. Pointing the parameter at a brand-new array, however, does not affect the caller's variable.

What is an oversized array?

An array created larger than the number of items currently stored, paired with a separate int variable that counts how many elements are in use. Items are kept in indexes 0 to size - 1, so items can be added and removed without creating a new array, until the array is full.

Suggest a change

Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written — several of these exist because somebody asked.