University College of Applied SciencesProgramming 1
العربية
Lecture 13 · 100 min

Arrays

How do we store thirty marks without thirty variables?

By the end of this lecture you will be able to

  1. Explain an array as a row of numbered boxes under one name
  2. Declare, create and initialise an array, and know its default values
  3. Read and write elements using the index and length
  4. Traverse an array with for and with enhanced for, and know when the second will not do
  5. Read an ArrayIndexOutOfBoundsException message and fix the <= length bug
  6. Pass an array to a method and return one from it, and explain why a method can change its elements
In this lecture
  1. Thirty marks in thirty variables is a program nobody wants to write
  2. An array is a row of numbered boxes under one name
  3. Three steps: declare, create, then give values
  4. A new array is filled with default values
  5. Indexes start at 0, and the last one is length - 1
  6. An element is read and written like any variable
  7. A for loop walks over the boxes one by one
  8. The same loop reads an array from the keyboard
  9. An index outside the array stops the program while it runs
  10. <= length is the most famous array bug
  11. Enhanced for reads every element without an index
  12. A method receives a whole array in one parameter
  13. A method cannot change a primitive argument, but it can change array elements
  14. A method can create a new array and return it
  15. Review questions
Part one: a row of boxes

Thirty marks in thirty variables is a program nobody wants to write

So far a variable holds one value. Five students in a section means five variables. Thirty students means thirty variables, thirty lines of reading and one very long addition.

The tiring way

Run the program, then imagine adding a sixth student: how many lines must change? Try it.

public class FiveMarks {
    public static void main(String[] args) {
        int mark1 = 85;
        int mark2 = 70;
        int mark3 = 92;
        int mark4 = 60;
        int mark5 = 77;
        int sum = mark1 + mark2 + mark3 + mark4 + mark5;
        System.out.println(sum);
    }
}
Output
384

An array is a row of numbered boxes under one name

marks[0]85int
marks[1]70int
marks[2]92int
marks[3]60int
marks[4]77int
  • Each box is an ordinary int variable, called an element.
  • The whole row has one name, marks, and each box has a number called its index.
  • All the elements of an array have the same type.
  • The number of boxes is set at creation and never changes.
VariableArray
One boxA row of boxes
Reached by its name: markAn element is reached by name and index: marks[2]
No indexThe index can be a variable: marks[i]

In the array above, which expression gives the mark 60, the fourth in the row?

Three steps: declare, create, then give values

Declare

int[] means an array of ints. This line reserves the name only; there are no boxes yet.

int[] marks;
Create

new creates the row with the number of boxes you ask for.

marks = new int[5];
Initialise

Put a value in each box, as with any variable.

marks[0] = 85;

The three steps in a program

Press "Debug line by line" and watch the row appear after the new line, then fill up. Add a fourth element: which two lines must change?

public class ThreeSteps {
    public static void main(String[] args) {
        int[] marks;
        marks = new int[3];
        marks[0] = 85;
        marks[1] = 70;
        marks[2] = 92;
        System.out.println(marks[0] + marks[1] + marks[2]);
    }
}
Output
247

If you already know the values, write them at once between curly brackets. All three steps happen in one line and the compiler counts the boxes itself: int[] marks = {85, 70, 92};

Declared but not created

Fix the program so it prints 85.

public class ForgotNew {
    public static void main(String[] args) {
        int[] marks;
        marks[0] = 85;
        System.out.println(marks[0]);
    }
}
Compiler messagemight not have been initialized
Show the fix
public class ForgotNew {
    public static void main(String[] args) {
        int[] marks = new int[3];
        marks[0] = 85;
        System.out.println(marks[0]);
    }
}
Output
85

Why? Declaring alone creates no boxes, so there is no marks[0] to write to. The message says marks has no value, because it is new that gives it a row.

Curly brackets only on the declaring line

Join the two lines into one so the program compiles.

public class BracesLater {
    public static void main(String[] args) {
        int[] marks;
        marks = {85, 70, 92};
        System.out.println(marks[2]);
    }
}
Compiler messageillegal start of expression
Show the fix
public class BracesLater {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92};
        System.out.println(marks[2]);
    }
}
Output
92

Why? The bare {...} form is allowed only on the declaring line itself. The message does not say so; it only says the compiler did not expect a bracket here, which is why it looks unrelated to the cause.

A new array is filled with default values

Element typeDefault value
int0
double0.0
booleanfalse
charThe character with code zero, invisible when printed
Stringnull

What is in the boxes before we write to them?

Predict the four lines before running, then add the line counts[0] = 5; before the printing and run again.

public class Defaults {
    public static void main(String[] args) {
        int[] counts = new int[3];
        double[] prices = new double[3];
        boolean[] paid = new boolean[3];
        String[] names = new String[3];

        System.out.println(counts[0]);
        System.out.println(prices[1]);
        System.out.println(paid[2]);
        System.out.println(names[0]);
    }
}
Output
0
0.0
false
null

Indexes start at 0, and the last one is length - 1

Every array keeps its box count in length. In an array of 4 elements the indexes are 0, 1, 2 and 3, so index 4 does not exist.

First, last and length

Add two elements inside the curly brackets and run. Notice the last element still prints correctly without changing the lines below.

public class IndexAndLength {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92, 60};
        System.out.println(marks.length);
        System.out.println(marks[0]);
        System.out.println(marks[marks.length - 1]);
    }
}
Output
4
85
60

length has no parentheses

public class LengthParens {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92};
        System.out.println(marks.length());
    }
}
Compiler messagecannot find symbol
Show the fix
public class LengthParens {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92};
        System.out.println(marks.length);
    }
}
Output
3

Why? An array's length is a stored value, not a method, so the parentheses send the compiler looking for a method of that name, and there is none.

Given int[] a = new int[10];, what is the largest allowed index?

An element is read and written like any variable

marks[1] is a full variable: it goes on the left of = to receive a value, on the right to be read, and it accepts ++ and +=. What goes in the brackets can be any expression that gives an int.

Draw the three boxes on paper and update them after each line. What is printed?

public class ReadWrite {
    public static void main(String[] args) {
        int[] a = new int[3];
        a[0] = 4;
        a[1] = a[0] + 5;
        a[2] = a[1] * 2;
        a[0] = a[2] - a[1];
        System.out.println(a[0]);
        System.out.println(a[1]);
        System.out.println(a[2]);
    }
}
Show the output
Output
9
9
18

Why? Each line reads what the boxes hold now: a[1] becomes 9, a[2] becomes 18, then a[0] changes from 4 to 18 − 9 = 9.

The index can be a variable or an expression

Predict the four lines, then run. Change i to 0 and predict again. What if i is 3? Try it; we will explain what happens shortly.

public class IndexExpression {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92, 60};
        int i = 1;
        System.out.println(marks[i]);
        System.out.println(marks[i + 1]);
        marks[i] = marks[i] + 10;
        marks[i + 1]++;
        System.out.println(marks[1]);
        System.out.println(marks[2]);
    }
}
Output
70
92
80
93
Part two: walking over the array

A for loop walks over the boxes one by one

The pattern you will write hundreds of times

Press "Debug line by line" and watch i move across the indexes. Then change the loop to print from last to first: start at marks.length - 1 and stop at 0.

public class Traverse {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92};
        for (int i = 0; i < marks.length; i++) {
            System.out.println("marks[" + i + "] = " + marks[i]);
        }
    }
}
Output
marks[0] = 85
marks[1] = 70
marks[2] = 92
PartWhy
int i = 0The first index
i < marks.lengthThe last index is one less than the length, and this stays right if the element count changes
i++The next box
marks[i]The current element

The same loop reads an array from the keyboard

We need not know the box count when writing the program: read the count first, create an array of that size, then fill it with a loop.

Read the marks, then print them

The input here is 3, then 85, 70 and 92. Notice the mark number shown to the user is i + 1, because people count from 1. Change the program to print the sum of the marks at the end.

import java.util.Scanner;

public class ReadMarks {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("How many marks? ");
        int n = in.nextInt();
        int[] marks = new int[n];

        for (int i = 0; i < marks.length; i++) {
            System.out.print("Mark " + (i + 1) + ": ");
            marks[i] = in.nextInt();
        }

        System.out.println();
        System.out.println("You entered:");
        for (int i = 0; i < marks.length; i++) {
            System.out.println(marks[i]);
        }
    }
}
Output
How many marks? Mark 1: Mark 2: Mark 3: 
You entered:
85
70
92

Print backwards

Read an int n, then n ints into an array. Print the elements from last to first, one per line. Print no prompts.

import java.util.Scanner;

public class Backwards {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // Read n, create the array, fill it, then print it backwards

    }
}
stdin
3
10 20 30
Expected output
30
20
10
Hint 1

You need two loops: one to read and one to print.

Hint 2

The printing loop: for (int i = n - 1; i >= 0; i--).

Solution
import java.util.Scanner;

public class Backwards {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] numbers = new int[n];
        for (int i = 0; i < n; i++) {
            numbers[i] = in.nextInt();
        }
        for (int i = n - 1; i >= 0; i--) {
            System.out.println(numbers[i]);
        }
    }
}

An index outside the array stops the program while it runs

Planned test: we break the program on purpose

The array has five elements, so marks[5] does not exist. Run the program and read the whole red message. Notice the compiler did not object, and Done was not printed. Change 5 to 7 and watch the number in the message change.

public class OutOfBounds {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92, 60, 77};
        System.out.println(marks[4]);
        System.out.println(marks[5]);
        System.out.println("Done");
    }
}
Output
77
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at OutOfBounds.main(OutOfBounds.java:5)
The real message from JDK 8
PartMeaning
ArrayIndexOutOfBoundsExceptionThe exception name: the index is outside the array
5The bad index itself, the most useful part of the message
OutOfBounds.java:5The file and line where the program stopped

What appears in normal output before the program stops?

public class CrashPoint {
    public static void main(String[] args) {
        int[] a = {1, 2, 3};
        int i = 2;
        System.out.println(a[i]);
        i++;
        System.out.println("i is " + i);
        System.out.println(a[i]);
        System.out.println("end");
    }
}
Show the output
Output
3
i is 3

Why? Lines run in order until the program reaches a[3]. It stops there without printing end, and an array does not give 0 for an index that does not exist.

<= length is the most famous array bug

Fix the loop

This program compiles, then stops while running after printing every element. Run it and read the number in the message: what was i? Fix the condition so the word Done appears, and use "Debug line by line" to see the last round.

public class LengthBug {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92};
        for (int i = 0; i <= marks.length; i++) {
            System.out.println(marks[i]);
        }
        System.out.println("Done");
    }
}
Output
85
70
92

Which loop visits every element of a with no error?

Enhanced for reads every element without an index

"For each mark in marks"

Read the line like this: for each mark in marks. In each round mark holds a copy of the next element. Add an element and print the sum of the elements.

public class EnhancedFor {
    public static void main(String[] args) {
        int[] marks = {85, 70, 92};
        for (int mark : marks) {
            System.out.println(mark);
        }
    }
}
Output
85
70
92

Does the first loop change the array's elements?

public class EnhancedCopy {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        for (int n : numbers) {
            n = n * 10;
        }
        for (int n : numbers) {
            System.out.println(n);
        }
    }
}
Show the output
Output
1
2
3

Why? n is a separate variable holding a copy of the element. Changing the copy does not reach the original box. The same idea returns shortly with methods.

You want toEnhanced forPlain for
Read every element in orderYes, and it is clearestYes
Know the element's indexNoYes
Change the array's elementsNoYes
Go from last to firstNoYes
Visit only part of the arrayNoYes
Compare an element with the nextNoYes

After the colon goes an array, not a number

public class ForEachLength {
    public static void main(String[] args) {
        int[] marks = {85, 70};
        for (int mark : marks.length) {
            System.out.println(mark);
        }
    }
}
Compiler messagefor-each not applicable to expression type
Show the fix
public class ForEachLength {
    public static void main(String[] args) {
        int[] marks = {85, 70};
        for (int mark : marks) {
            System.out.println(mark);
        }
    }
}
Output
85
70

Why? marks.length is a single number, and enhanced for needs something it can walk over element by element.

Part three: arrays and methods

A method receives a whole array in one parameter

A method that works with any length

The parameter type is int[], and in the call we pass just the name. Call total with a third array of one element.

public class ArrayParameter {
    static int total(int[] numbers) {
        int sum = 0;
        for (int n : numbers) {
            sum += n;
        }
        return sum;
    }

    public static void main(String[] args) {
        int[] section1 = {85, 70, 92};
        int[] section2 = {60, 77};
        System.out.println(total(section1));
        System.out.println(total(section2));
    }
}
Output
247
137

No square brackets in the call

public class CallBrackets {
    static int first(int[] numbers) {
        return numbers[0];
    }

    public static void main(String[] args) {
        int[] marks = {85, 70};
        System.out.println(first(marks[]));
    }
}
Compiler message'.class' expected
Show the fix
public class CallBrackets {
    static int first(int[] numbers) {
        return numbers[0];
    }

    public static void main(String[] args) {
        int[] marks = {85, 70};
        System.out.println(first(marks));
    }
}
Output
85

Why? int[] belongs in the method definition to state the type; in the call we write just the array name. The message '.class' expected looks very strange, but this is usually why it appears.

A method cannot change a primitive argument, but it can change array elements

In the methods lecture our attempt to write a method that swaps two variables failed: arguments pass by value, so the method works on a copy. Run both examples under the debugger and compare.

Remember: the failed swap

Press "Debug line by line". Inside swap, a and b trade values, but they are copies. Back in main, x and y have not changed.

public class FailedSwap {
    static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

    public static void main(String[] args) {
        int x = 5;
        int y = 9;
        swap(x, y);
        System.out.println(x + " " + y);
    }
}
Output
5 9

The same swap inside an array works

Debug line by line and stop inside swap. Notice arr and pair point to the same row, so what the method writes, main sees.

public class ArraySwap {
    static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
        int[] pair = {5, 9};
        swap(pair, 0, 1);
        System.out.println(pair[0] + " " + pair[1]);
    }
}
Output
9 5
What the variable holdsWhat reaches the methodIs main affected?
int x: the value 5 itselfA copy of 5No
int[] pair: an arrow pointing to the rowA copy of the arrow, pointing to the same rowYes, in the elements

Two similar methods, one taking an int, the other an int[]. What does the program print?

public class DoubleBoth {
    static void doubleValue(int x) {
        x = x * 2;
    }

    static void doubleAll(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * 2;
        }
    }

    public static void main(String[] args) {
        int n = 5;
        int[] a = {3, 4};
        doubleValue(n);
        doubleAll(a);
        System.out.println(n);
        System.out.println(a[0]);
        System.out.println(a[1]);
    }
}
Show the output
Output
5
6
8

Why? doubleValue changed only its copy of 5. doubleAll wrote into the row that a points to.

The same thing without a method: int[] b = a;. Do we now have two rows?

public class TwoNames {
    public static void main(String[] args) {
        int[] a = {1, 2, 3};
        int[] b = a;
        b[0] = 99;
        System.out.println(a[0]);
        System.out.println(b[0]);
    }
}
Show the output
Output
99
99

Why? Only new creates a new row. int[] b = a; copied the arrow, so the one row now has two names.

A bonus method

Write the method static void addBonus(int[] marks, int bonus) that raises each mark by bonus inside the same array, never going above 100. In main read n, then n marks, then bonus. Call the method and print the marks, one per line.

import java.util.Scanner;

public class Bonus {
    // Write addBonus here

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // Read the input, call addBonus, print the marks

    }
}
stdin
3
50 90 70
5
Expected output
55
95
75
Hint 1

To change elements you need plain for; the enhanced one works on a copy.

Hint 2

The method returns nothing: main sees the change in the same array.

Solution
import java.util.Scanner;

public class Bonus {
    static void addBonus(int[] marks, int bonus) {
        for (int i = 0; i < marks.length; i++) {
            marks[i] = marks[i] + bonus;
            if (marks[i] > 100) {
                marks[i] = 100;
            }
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] marks = new int[n];
        for (int i = 0; i < n; i++) {
            marks[i] = in.nextInt();
        }
        int bonus = in.nextInt();
        addBonus(marks, bonus);
        for (int mark : marks) {
            System.out.println(mark);
        }
    }
}

A method can create a new array and return it

A method whose return type is int[]

Press "Debug line by line". result ends when the method ends, but the row survives because main took the arrow to it. Change the method to return cubes instead of squares.

public class ReturnArray {
    static int[] squares(int n) {
        int[] result = new int[n];
        for (int i = 0; i < n; i++) {
            result[i] = (i + 1) * (i + 1);
        }
        return result;
    }

    public static void main(String[] args) {
        int[] s = squares(4);
        for (int value : s) {
            System.out.println(value);
        }
    }
}
Output
1
4
9
16

The first even numbers

Write the method static int[] firstEvens(int n) that returns an array holding the first n even numbers: 2, 4, 6 and so on. In main read n and print the elements, one per line.

import java.util.Scanner;

public class FirstEvens {
    // Write firstEvens here

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // Read n, call firstEvens, print the result

    }
}
stdin
4
Expected output
2
4
6
8
Hint 1

The element at index i equals (i + 1) * 2.

Solution
import java.util.Scanner;

public class FirstEvens {
    static int[] firstEvens(int n) {
        int[] evens = new int[n];
        for (int i = 0; i < n; i++) {
            evens[i] = (i + 1) * 2;
        }
        return evens;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for (int value : firstEvens(n)) {
            System.out.println(value);
        }
    }
}

From mark to percentage

Write the method static double[] toPercent(int[] marks, int outOf) that returns a new array holding each mark as a percentage, leaving the original unchanged. In main read n, then outOf, then n marks. Print each percentage on its own line, then print the first original mark.

import java.util.Scanner;

public class Percent {
    // Write toPercent here

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // Read the input, call toPercent, print the results

    }
}
stdin
2 50
45 25
Expected output
90.0
50.0
45
Hint 1

The new array has length marks.length and type double[].

Hint 2

Remember integer division: write marks[i] * 100.0 / outOf.

Solution
import java.util.Scanner;

public class Percent {
    static double[] toPercent(int[] marks, int outOf) {
        double[] result = new double[marks.length];
        for (int i = 0; i < marks.length; i++) {
            result[i] = marks[i] * 100.0 / outOf;
        }
        return result;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int outOf = in.nextInt();
        int[] marks = new int[n];
        for (int i = 0; i < n; i++) {
            marks[i] = in.nextInt();
        }
        for (double p : toPercent(marks, outOf)) {
            System.out.println(p);
        }
        System.out.println(marks[0]);
    }
}

Review questions

What does new double[4] hold right after it is created?

Which task can enhanced for not do?

A program stops with ArrayIndexOutOfBoundsException: 3. What does 3 mean?

This method creates a new row and writes to it. What does the program print?

public class Replace {
    static void replace(int[] arr) {
        arr = new int[2];
        arr[0] = 9;
    }

    public static void main(String[] args) {
        int[] a = {1, 2};
        replace(a);
        System.out.println(a[0]);
    }
}
Show the output
Output
1

Why? arr is a copy of the arrow. The first line made that copy point to a new row, so a still points to the old one. A method can change the elements of a row it reaches, but not the arrow held in main.