Home > Articles

This chapter is from the book

3.10. Arrays

Arrays hold sequences of values of the same type. In the following sections, you will see how to work with arrays in Java.

3.10.1. Declaring Arrays

Declare an array variable by specifying the array type—which is the element type followed by []—and the array variable name. For example, here is the declaration of an array a of integers:

int[] a;

However, this statement only declares the variable a. It does not yet initialize a with an actual array. Use the new operator to create the array.

int[] a = new int[100]; // or var a = new int[100];

This statement declares and initializes an array of 100 integers.

The array length need not be a constant: new int[n] creates an array of length n.

Once you create an array, you cannot change its length (although you can, of course, change an individual array element). If you frequently need to expand the length of arrays while your program is running, you should use array lists, which are covered in Chapter 5.

The type of an array variable does not include the length. For example, the variable a in the preceding example has type int[] and can be set to an int array of any length.

Java has a shortcut for creating an array object and supplying initial values:

int[] smallPrimes = { 2, 3, 5, 7, 11, 13 };

Notice that you do not use new with this syntax, and you don’t specify the length.

A comma after the last value is allowed, which can be convenient for an array to which you keep adding values over time:

String[] authors = {
    "James Gosling",
    "Bill Joy",
    "Guy Steele",
    // add more names here and put a comma after each name
};

You can declare an anonymous array:

new int[] { 17, 19, 23, 29, 31, 37 }

This expression allocates a new array and fills it with the values inside the braces. It counts the number of initial values and sets the array length accordingly. You can use this syntax to reinitialize an array without creating a new variable. For example,

smallPrimes = new int[] { 17, 19, 23, 29, 31, 37 };

is shorthand for

int[] anonymous = { 17, 19, 23, 29, 31, 37 };
smallPrimes = anonymous;

3.10.2. Accessing Array Elements

You access each individual element of an array through an integer index, using the bracket operator. For example, if a is an array of integers, then a[i] is the element with index i in the array.

The array elements are numbered starting from 0. The last valid index is one less than the length. In the example below, the index values range from 0 to 99. Once the array is created, you can fill the elements in an array, for example, by using a loop:

int[] a = new int[100];
for (int i = 0; i < 100; i++)
    a[i] = i; // fills the array with numbers 0 to 99

When you create an array of numbers, all elements are initialized with zero. Arrays of boolean are initialized with false. Arrays of objects are initialized with the special value null, which indicates that they do not (yet) hold any objects. This can be surprising for beginners. For example,

String[] names = new String[10];

creates an array of ten strings, all of which are null. If you want the array to hold empty strings, you must supply them:

for (int i = 0; i < 10; i++) names[i] = "";

To find the number of elements of an array, use array.length. For example:

for (int i = 0; i < a.length; i++)
    IO.println(a[i]);

3.10.3. The “for each” Loop

Java has a powerful looping construct that allows you to loop through each element in an array (or any other collection of elements) without having to fuss with index values.

The enhanced for loop

for (variable : collection) statement

sets the given variable to each element of the collection and then executes the statement (which, of course, may be a block). The collection expression must be an array or an object of a class that implements the Iterable interface, such as ArrayList. Array lists are covered in Chapter 5 and the Iterable interface in Chapter 9.

For example,

for (int element : a)
    IO.println(element);

prints each element of the array a on a separate line.

You should read this loop as “for each element in a.” The designers of the Java language considered using keywords, such as foreach and in. But this loop was a late addition to the Java language, and in the end nobody wanted to break the old code that already contained methods or variables with these names (such as System.in).

Of course, you could achieve the same effect with a traditional for loop:

for (int i = 0; i < a.length; i++)
    IO.println(a[i]);

However, the “for each” loop is more concise and less error-prone, as you don’t have to worry about those pesky start and end index values.

The “for each” loop is a pleasant improvement over the traditional loop if you need to process all elements in a collection. However, there are still plenty of opportunities to use the traditional for loop. For example, you might not want to traverse the entire collection, or you may need the index value inside the loop.

3.10.4. Array Copying

You can copy one array variable into another, but then both variables refer to the same array:

int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12; // now smallPrimes[5] is also 12

Figure 3.14 shows the result.

FIGURE 3.14

Figure 3.14: Copying an array variable

If you actually want to copy all values of one array into a new array, use the copyOf method in the Arrays class:

int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);

The second argument is the length of the new array. A common use of this method is to increase the length of an array:

luckyNumbers = Arrays.copyOf(luckyNumbers, 2 * luckyNumbers.length);

The additional elements are filled with 0 if the array contains numbers, false if the array contains boolean values. Conversely, if the length is less than the length of the original array, only the initial values are copied.

3.10.5. Command-Line Arguments

If you want to process arguments that a user of your program specified on the command line, your main method needs a parameter that is an array of strings.

For example, consider this program in a file Message.java:

void main(String[] args) {
    IO.print(switch (args[0])) {
        case "-a" -> "🏴‍☠️";
        case "-b" -> "🍺";
        case "-h" -> "Hello,";
        default -> args[0];
    }
    IO.print(" " + args[1]);
    IO.println("!");
}

If the program is called as

java Message.java -h World

or

javac Message.java
java Message -h World

then args[0] is the string "-h", and args[1] is "World".

3.10.6. Array Sorting

To sort an array of numbers, you can use one of the sort methods in the Arrays class:

int[] a = new int[10000];
. . .
Arrays.sort(a)

This method uses a tuned version of the QuickSort algorithm that is claimed to be very efficient on most data sets. The Arrays class provides several other convenience methods for arrays that are included in the API notes at the end of this section.

The program in Listing 3.7 puts arrays to work. This program draws a random combination of numbers for a lottery game. For example, if you play a “choose 6 numbers from 49” lottery, the program might print this:

Bet the following combination. It'll make you rich!
4
7
8
19
30
44

To select such a random set of numbers, first fill an array numbers with the values 1, 2, . . ., n:

int[] numbers = new int[n];
for (int i = 0; i < numbers.length; i++)
    numbers[i] = i + 1;

A second array holds the numbers to be drawn:

int[] result = new int[k];

Now draw k numbers. The Math.random method returns a random floating-point number that is between 0 (inclusive) and 1 (exclusive). Multiplying the result with n yields a random number between 0 and n – 1.

int r = (int) (Math.random() * n);

Set the ith result to be the number at that index. Initially, that is just r + 1, but as you’ll see presently, the contents of the numbers array are changed after each draw.

result[i] = numbers[r];

Now, you must be sure never to draw that number again—all lottery numbers must be distinct. Therefore, overwrite numbers[r] with the last number in the array and reduce n by 1.

numbers[r] = numbers[n - 1];
n--;

The point is that in each draw we pick an index, not the actual value. The index points into an array that contains the values that have not yet been drawn.

After drawing k lottery numbers, sort the result array for a more pleasing output:

Arrays.sort(result);
for (int r : result)
    IO.println(r);

Listing 3.7 LotteryDrawing.java

/**
 * This program demonstrates array manipulation.
 */
void main() {
    int k = Integer.parseInt(IO.readln("How many numbers do you need to draw? "));
    int n = Integer.parseInt(IO.readln("What is the highest number you can draw? "));

    // fill an array with numbers 1 2 3 . . . n
    int[] numbers = new int[n];
    for (int i = 0; i < numbers.length; i++)
        numbers[i] = i + 1;

    // draw k numbers and put them into a second array
    int[] result = new int[k];
    for (int i = 0; i < result.length; i++) {
        // make a random index between 0 and n - 1
        int r = (int) (Math.random() * n);

        // pick the element at the random location
        result[i] = numbers[r];

        // move the last element into the random location
        numbers[r] = numbers[n - 1];
        n--;
    }

    // print the sorted array
    Arrays.sort(result);
    IO.println("Bet the following combination. It'll make you rich!");
    for (int r : result)
        IO.println(r);
}

3.10.7. Multidimensional Arrays

Multidimensional arrays use more than one index to access array elements. They are used for tables and other more complex arrangements. You can safely skip this section until you have a need for this storage mechanism.

Suppose you want to make a table of numbers that shows how much an investment of $10,000 will grow under different interest rate scenarios in which interest is paid annually and reinvested.

        5%        6%        7%        8%        9%       10%
  10000.00  10000.00  10000.00  10000.00  10000.00  10000.00
  10500.00  10600.00  10700.00  10800.00  10900.00  11000.00
  11025.00  11236.00  11449.00  11664.00  11881.00  12100.00
  11576.25  11910.16  12250.43  12597.12  12950.29  13310.00
  12155.06  12624.77  13107.96  13604.89  14115.82  14641.00
  12762.82  13382.26  14025.52  14693.28  15386.24  16105.10
  13400.96  14185.19  15007.30  15868.74  16771.00  17715.61
  14071.00  15036.30  16057.81  17138.24  18280.39  19487.17
  14774.55  15938.48  17181.86  18509.30  19925.63  21435.89
  15513.28  16894.79  18384.59  19990.05  21718.93  23579.48

You can store this information in a two-dimensional array named balances.

Declaring a two-dimensional array in Java is simple enough. For example:

double[][] balances;

You cannot use the array until you initialize it. In this case, you can do the initialization as follows:

balances = new double[NYEARS][NRATES];

In other cases, if you know the array elements, you can use a shorthand notation for initializing a multidimensional array without a call to new. For example:

int[][] magicSquare = {
    { 16, 3, 2, 13 },
    { 5, 10, 11, 8 },
    { 9, 6, 7, 12 },
    { 4, 15, 14, 1 }
};

Once the array is initialized, you can access individual elements by supplying two pairs of brackets—for example, balances[i][j].

The example program stores a one-dimensional array interestRates of interest rates and a two-dimensional array balances of account balances, one for each year and interest rate. Initialize the first row of the array with the initial balance:

for (int j = 0; j < balances[0].length; j++)
    balances[0][j] = 10000;

Then compute the other rows, as follows:

for (int i = 1; i < balances.length; i++) {
    for (int j = 0; j < balances[i].length; j++) {
        double oldBalance = balances[i - 1][j];
        double interest = . . .;
        balances[i][j] = oldBalance + interest;
    }
}

Listing 3.8 shows the full program. In this program, you can see how to use multiple methods. The main method calls a printTable method that prints the table of balances.

Listing 3.8 CompoundInterest.java

/**
 * This program shows how to store tabular data in a 2D array.
 */
void main() {
    final double STARTRATE = 5;
    final int NRATES = 6;
    final int NYEARS = 10;

    // set interest rates to 5 . . . 10%
    double[] interestRates = new double[NRATES];
    for (int j = 0; j < interestRates.length; j++)
        interestRates[j] = (STARTRATE + j) / 100.0;

    double[][] balances = new double[NYEARS][NRATES];

    // set initial balances to 10000
    for (int j = 0; j < balances[0].length; j++)
        balances[0][j] = 10000;

    // compute interest for future years
    for (int i = 1; i < balances.length; i++) {
        for (int j = 0; j < balances[i].length; j++) {
            // get last year's balances from previous row
            double oldBalance = balances[i - 1][j];

            // compute interest
            double interest = oldBalance * interestRates[j];

            // compute this year's balances
            balances[i][j] = oldBalance + interest;
        }
    }

    printTable(interestRates, balances);
}

void printTable(double[] headers, double[][] values) {
    for (double header : headers) {
        IO.print("%10.2f".formatted(header));
    }
    IO.println();
    IO.println("-".repeat(10 * headers.length));
    // print balance table
    for (double[] row : values) {
        // print table row
        for (double value : row)
            IO.print("%10.2f".formatted(value));

        IO.println();
    }
}

3.10.8. Ragged Arrays

So far, what you have seen is not too different from other programming languages. But there is actually something subtle going on behind the scenes that you can sometimes turn to your advantage: Java has no multidimensional arrays at all, only one-dimensional arrays. Multidimensional arrays are faked as “arrays of arrays.”

For example, the balances array in the preceding example is actually an array that contains ten elements, each of which is an array of six floating-point numbers (Figure 3.15).

FIGURE 3.16

Figure 3.15: A two-dimensional array

The expression balances[i] refers to the ith subarray—that is, the ith row of the table. It is itself an array, and balances[i][j] refers to the jth element of that array.

Since rows of arrays are individually accessible, you can actually swap them!

double[] temp = balances[i];
balances[i] = balances[i + 1];
balances[i + 1] = temp;

Note that the number of rows and columns is not a part of the type of an array variable. The variable balances has type double[][]: an array of double arrays.

Therefore, you can make “ragged” arrays—that is, arrays in which different rows have different lengths. Here is the standard example. Let us make an array in which the element at row i and column j equals the number of possible outcomes of a “choose j numbers from i numbers” lottery.

1
1  1
1  2  1
1  3  3  1
1  4  6  4  1
1  5 10 10  5 1
1  6 15 20 15 6 1

As j can never be larger than i, the matrix is triangular. The ith row has i + 1 elements. (It is OK to choose 0 elements; there is one way to make such a choice.) To build this ragged array, first allocate the array holding the rows:

final int NMAX = 10;
int[][] odds = new int[NMAX + 1][];

Next, allocate the rows:

for (int n = 0; n <= NMAX; n++)
    odds[n] = new int[n + 1];

Now that the array is allocated, you can access the elements in the normal way, provided you do not overstep the bounds:

for (int n = 0; n < odds.length; n++) {
    for (int k = 0; k < odds[n].length; k++) {
        // compute lotteryOdds
        . . .
        odds[n][k] = lotteryOdds;
    }
}

Listing 3.9 gives the complete program.

Listing 3.9 LotteryArray.java

/**
 * This program demonstrates a triangular array.
 */
void main() {
    final int NMAX = 10;

    // allocate triangular array
    int[][] odds = new int[NMAX + 1][];
    for (int n = 0; n <= NMAX; n++)
        odds[n] = new int[n + 1];

    // fill triangular array
    for (int n = 0; n < odds.length; n++)
        for (int k = 0; k < odds[n].length; k++) {
            /*
             * compute binomial coefficient
             * n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
             */
            int lotteryOdds = 1;
            for (int i = 1; i <= k; i++)
                lotteryOdds = lotteryOdds * (n - i + 1) / i;

            odds[n][k] = lotteryOdds;
        }

    // print triangular array
    for (int[] row : odds) {
        for (int odd : row)
            IO.print("%4d".formatted(odd));
        IO.println();
    }
}

You have now seen the fundamental programming structures of the Java language. The next chapter covers object-oriented programming in Java.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.