Arrays
An array is a data structure that stores a collection of values of the same type. You access each individual value through an integer index. For example, if a is an array of integers, then a[i] is the ith integer in the array.
You 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. You use the new operator to create the array.
int[] a = new int[100];
This statement sets up an array that can hold 100 integers. The array entries are numbered from 0 to 99 (and not 1 to 100). Once the array is created, you can fill the entries 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 0 to 99
If you construct an array with 100 elements and then try to access the element a[100] (or any other index outside the range 0 . . . 99), then your program will terminate with an “array index out of bounds” exception.
If you construct an array with 100 elements and then try to access the element a[100] (or any other index outside the range 0 . . . 99), then your program will terminate with an “array index out of bounds” exception.
To find the number of elements of an array, use arrayName.length. For example,
for (int i = 0; i < a.length; i++) System.out.println(a[i]);
Once you create an array, you cannot change its size (although you can, of course, change an individual array element). If you frequently need to expand the size of an array while a program is running, you should use a different data structure called an array list. (See Chapter 5 for more on array lists.)
You can define an array variable either as
int[] a;
or as
int a[];
Most Java programmers prefer the former style because it neatly separates the type int[] (integer array) from the variable name.
You can define an array variable either as
int[] a;
or as
int a[];
Most Java programmers prefer the former style because it neatly separates the type int[] (integer array) from the variable name.
Array Initializers and Anonymous Arrays
Java has a shorthand to create an array object and supply initial values at the same time. Here's an example of the syntax at work:
int[] smallPrimes = { 2, 3, 5, 7, 11, 13 };
Notice that you do not use a call to new when you use this syntax.
You can even initialize 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 size 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 a shorthand for
int[] anonymous = { 17, 19, 23, 29, 31, 37 }; smallPrimes = anonymous;
It is legal to have arrays of length 0. Such an array can be useful if you write a method that computes an array result, and the result happens to be empty. You construct an array of length 0 as
new elementType[0]
Note that an array of length 0 is not the same as null. (See Chapter 4 for more information about null.)
It is legal to have arrays of length 0. Such an array can be useful if you write a method that computes an array result, and the result happens to be empty. You construct an array of length 0 as
new elementType[0]
Note that an array of length 0 is not the same as null. (See Chapter 4 for more information about null.)
Copying Arrays
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. If you actually want to copy all values of one array into another, you have to use the arraycopy method in the System class. The syntax for this call is
System.arraycopy(from, fromIndex, to, toIndex, count);
Figure 3-14. Copying an array variable
The to array must have sufficient space to hold the copied elements.
For example, the following statements, whose result is illustrated in Figure 3-15, set up two arrays and then copy the last four entries of the first array to the second array. The copy starts at position 2 in the source array and copies 4 entries, starting at position 3 of the target.
int[] smallPrimes = {2, 3, 5, 7, 11, 13}; int[] luckyNumbers = {1001, 1002, 1003, 1004, 1005, 1006, 1007}; System.arraycopy(smallPrimes, 2, luckyNumbers, 3, 4); for (int i = 0; i < luckyNumbers.length; i++) System.out.println(i + ": " + luckyNumbers[i]);
Figure 3-15. Copying values between arrays
The output is:
0: 1001 1: 1002 2: 1003 3: 5 4: 7 5: 11 6: 13
A Java array is quite different from a C++ array on the stack. It is, however, essentially the same as a pointer to an array allocated on the heap. That is,
int[] a = new int[100]; // Java
is not the same as
int a[100]; // C++
but rather
int* a = new int[100]; // C++
In Java, the [] operator is predefined to perform bounds checking. Furthermore, there is no pointer arithmetic—you can't increment a to point to the next element in the array.
A Java array is quite different from a C++ array on the stack. It is, however, essentially the same as a pointer to an array allocated on the heap. That is,
int[] a = new int[100]; // Java
is not the same as
int a[100]; // C++
but rather
int* a = new int[100]; // C++
In Java, the [] operator is predefined to perform bounds checking. Furthermore, there is no pointer arithmetic—you can't increment a to point to the next element in the array.
Command Line Parameters
You have already seen one example of Java arrays repeated quite a few times. Every Java program has a main method with a String[] args parameter. This parameter indicates that the main method receives an array of strings, namely, the arguments specified on the command line.
For example, consider this program:
public class Message { public static void main(String[] args) { if (args[0].equals("-h")) System.out.print("Hello,"); else if (args[0].equals("-g")) System.out.print("Goodbye,"); // print the other command line arguments for (int i = 1; i < args.length; i++) System.out.print(" " + args[i]); System.out.println("!"); } }
If the program is called as
java Message -g cruel world
then the args array has the following contents:
args[0]: "-g" args[1]: "cruel" args[2]: "world"
The program prints the message
Goodbye, cruel world!
In the main method of a Java program, the name of the program is not stored in the args array. For example, when you start up a program as
java Message -h world
from the command line, then args[0] will be "-h" and not "Message" or "java".
In the main method of a Java program, the name of the program is not stored in the args array. For example, when you start up a program as
java Message -h world
from the command line, then args[0] will be "-h" and not "Message" or "java".
Sorting an Array
If you want 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 Example 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, then the program might print:
Bet the following combination. It'll make you rich! 4 7 8 19 30 44
To select such a random set of numbers, we 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 we draw k numbers. The Math.random method returns a random floating point number that is between 0 (inclusive) and 1 (exclusive). By multiplying the result with n, we obtain a random number between 0 and n - 1.
int r = (int)(Math.random() * n);
We set the ith result to be the number at that index. Initially, that is just r itself, but as you'll see presently, the contents of the numbers array is changed after each draw.
result[i] = numbers[r];
Now we must be sure never to draw that number again—all lottery numbers must be distinct. Therefore, we 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, we sort the result array for a more pleasing output:
Arrays.sort(result); for (int i = 0; i < result.length; i++) System.out.println(result[i]);
Example 3-7 LotteryDrawing.java
1. import java.util.*; 2. import javax.swing.*; 3. 4. public class LotteryDrawing 5. { 6. public static void main(String[] args) 7. { 8. String input = JOptionPane.showInputDialog 9. ("How many numbers do you need to draw?"); 10. int k = Integer.parseInt(input); 11. 12. input = JOptionPane.showInputDialog 13. ("What is the highest number you can draw?"); 14. int n = Integer.parseInt(input); 15. 16. // fill an array with numbers 1 2 3 . . . n 17. int[] numbers = new int[n]; 18. for (int i = 0; i < numbers.length; i++) 19. numbers[i] = i + 1; 20. 21. // draw k numbers and put them into a second array 22. 23. int[] result = new int[k]; 24. for (int i = 0; i < result.length; i++) 25. { 26. // make a random index between 0 and n - 1 27. int r = (int)(Math.random() * n); 28. 29. // pick the element at the random location 30. result[i] = numbers[r]; 31. 32. // move the last element into the random location 33. numbers[r] = numbers[n - 1]; 34. n--; 35. } 36. 37. // print the sorted array 38. 39. Arrays.sort(result); 40. System.out.println 41. ("Bet the following combination. It'll make you rich!"); 42. for (int i = 0; i < result.length; i++) 43. System.out.println(result[i]); 44. 45. System.exit(0); 46. } 47. }
java.lang.System 1.1
-
static void arraycopy(Object from, int fromIndex, Object to, int toIndex, int count)
Parameters:
from
an array of any type (Chapter 5 explains why this is a parameter of type Object)
fromIndex
the starting index from which to copy elements
to
an array of the same type as from
toIndex
the starting index to which to copy elements
count
the number of elements to copy
copies elements from the first array to the second array.
java.util.Arrays 1.2
-
static void sort(Xxx[] a)
Parameters:
a
an array of type int, long, short, char, byte, boolean, float or double
sorts the array, using a tuned QuickSort algorithm.
-
static int binarySearch(Xxx[] a, Xxx v)
Parameters:
a
a sorted array of type int, long, short, char, byte, boolean, float or double
v
a value of the same type as the elements of a
uses the BinarySearch algorithm to search for the value v. If it is found, its index is returned. Otherwise, a negative value r is returned; -r - 1 is the spot at which v should be inserted to keep a sorted.
-
static void fill(Xxx[] a, Xxx v)
Parameters:
a
an array of type int, long, short, char, byte, boolean, float or double
v
a value of the same type as the elements of a
sets all elements of the array to v.
-
static boolean equals(Xxx[] a, Object other)
Parameters:
a
an array of type int, long, short, char, byte, boolean, float or double
other
an object
returns true if other is an array of the same type, if it has the same length, and if the elements in corresponding indexes match.
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. Table 3-5 illustrates this scenario.
The obvious way to store this information is in a two-dimensional array (or matrix), which we will call balance.
Declaring a matrix in Java is simple enough. For example:
double[][] balance;
As always, you cannot use the array until you initialize it with a call to new. In this case, you can do the initialization as follows:
balance = new double[NYEARS][NRATES];
In other cases, if you know the array elements, you can use a shorthand notion for initializing multidimensional arrays without needing a call to new. For example;
int[][] magicSquare = { {16, 3, 2, 13}, {5, 10, 11, 8}, {9, 6, 7, 12}, {4, 15, 14, 1} };
Table 3-5. Growth of an investment at different interest rates
10% |
11% |
12% |
13% |
14% |
15% |
---|---|---|---|---|---|
$10,000.00 |
$10,000.00 |
$10,000.00 |
$10,000.00 |
$10,000.00 |
$10,000.00 |
$11,000.00 |
$11,100.00 |
$11,200.00 |
$11,300.00 |
$11,400.00 |
$11,500.00 |
$12,100.00 |
$12,321.00 |
$12,544.00 |
$12,769.00 |
$12,996.00 |
$13,225.00 |
$13,310.00 |
$13,676.31 |
$14,049.28 |
$14,428.97 |
$14,815.44 |
$15,208.75 |
$14,641.00 |
$15,180.70 |
$15,735.19 |
$16,304.74 |
$16,889.60 |
$17,490.06 |
$16,105.10 |
$16,850.58 |
$17,623.42 |
$18,424.35 |
$19,254.15 |
$20,113.57 |
$17,715.61 |
$18,704.15 |
$19,738.23 |
$20,819.52 |
$21,949.73 |
$23,130.61 |
$19,487.17 |
$20,761.60 |
$22,106.81 |
$23,526.05 |
$25,022.69 |
$26,600.20 |
$21,435.89 |
$23,045.38 |
$24,759.63 |
$26,584.44 |
$28,525.86 |
$30,590.23 |
$23,579.48 |
$25,580.37 |
$27,730.79 |
$30,040.42 |
$32,519.49 |
$35,178.76 |
Once the array is initialized, you can access individual elements, by supplying two brackets, for example balance[i][j].
The example program stores a one-dimensional array interest of interest rates and a two-dimensional array balance of account balances, one for each year and interest rate. We initialize the first row of the array with the initial balance:
for (int j = 0; j < balance[0].length; j++) balance[0][j] = 10000;
Then we compute the other rows, as follows:
for (int i = 1; i < balance.length; i++) { for (int j = 0; j < balance[i].length; j++) { double oldBalance = balance[i - 1][j]; double interest = . . .; balance[i][j] = oldBalance + interest; } }
Example 3-8 shows the full program.
Example 3-8 CompoundInterest.java
1. import java.text.*; 2. import javax.swing.*; 3. 4. public class CompoundInterest 5. { 6. public static void main(String[] args) 7. { 8. final int STARTRATE = 10; 9. final int NRATES = 6; 10. final int NYEARS = 10; 11. 12. // set interest rates to 10 . . . 15% 13. double[] interestRate = new double[NRATES]; 14. for (int j = 0; j < interestRate.length; j++) 15. interestRate[j] = (STARTRATE + j) / 100.0; 16. 17. double[][] balance = new double[NYEARS][NRATES]; 18. 19. // set initial balances to 10000 20. for (int j = 0; j < balance[0].length; j++) 21. balance[0][j] = 10000; 22. 23. // compute interest for future years 24. 25. for (int i = 1; i < balance.length; i++) 26. { 27. for (int j = 0; j < balance[i].length; j++) 28. { 29. // get last year's balance from previous row 30. double oldBalance = balance[i - 1][j]; 31. 32. // compute interest 33. double interest = oldBalance * interestRate[j]; 34. 35. // compute this year's balance 36. balance[i][j] = oldBalance + interest; 37. } 38. } 39. 40. // print one row of interest rates 41. 42. NumberFormat formatter = NumberFormat.getPercentInstance(); 43. 44. for (int j = 0; j < interestRate.length; j++) 45. { 46. System.out.print(" "); 47. System.out.print(formatter.format(interestRate[j])); 48. } 49. System.out.println(); 50. 51. // print balance table 52. 53. formatter = NumberFormat.getCurrencyInstance(); 54. 55. for (int i = 0; i < balance.length; i++) 56. { 57. // print table row 58. for (int j = 0; j < balance[i].length; j++) 59. { 60. System.out.print(" "); 61. System.out.print(formatter.format(balance[i][j])); 62. } 63. System.out.println(); 64. } 65. } 66. }
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 balance array in the preceding example is actually an array that contains ten elements, each of which is an array of six floating-point numbers (see Figure 3-16).
Figure 3-16. A two-dimensional array
The expression balance[i] refers to the ith subarray, that is, the ith row of the table. It is, itself, an array, and balance[i][j] refers to the jth entry of that array.
Because rows of arrays are individually accessible, you can actually swap them!
double[] temp = balance[i]; balance[i] = balance[i + 1]; balance[i + 1] = temp;
It is also easy to 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 entry 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
Because j can never be larger than i, the matrix is triangular. The ith row has i + 1 elements. (We allow choosing 0 elements; there is one way to make such a choice.) To build this ragged array, first allocate the array holding the rows.
int[][] odds = new int[NMAX + 1][];
Next, allocate the rows.
for (n = 0; n <= NMAX; n++) odds[n] = new int[n + 1];
Now that the array is allocated, we can access the elements in the normal way, provided we do not overstep the bounds.
for (n = 0; n < odds.length; n++) for (k = 0; k < odds[n].length; k++) { // compute lotteryOdds . . . odds[n][k] = lotteryOdds; }
Example 3-9 gives the complete program.
The Java declaration
double[][] balance = new double[10][6]; // Java
is not the same as
double balance[10][6]; // C++
or even
double (*balance)[6] = new double[10][6]; // C++
in C++. Instead, an array of ten pointers is allocated:
double** balance = new double*[10]; // C++
Then, each element in the pointer array is filled with an array of 6 numbers:
for (i = 0; i < 10; i++) balance[i] = new double[6];
Mercifully, this loop is automatic when you ask for a new double[10][6]. When you want ragged arrays, you allocate the row arrays separately.
The Java declaration
double[][] balance = new double[10][6]; // Java
is not the same as
double balance[10][6]; // C++
or even
double (*balance)[6] = new double[10][6]; // C++
in C++. Instead, an array of ten pointers is allocated:
double** balance = new double*[10]; // C++
Then, each element in the pointer array is filled with an array of 6 numbers:
for (i = 0; i < 10; i++) balance[i] = new double[6];
Mercifully, this loop is automatic when you ask for a new double[10][6]. When you want ragged arrays, you allocate the row arrays separately.
Example 3-9 LotteryArray.java
1. public class LotteryArray 2. { 3. public static void main(String[] args) 4. { 5. final int NMAX = 10; 6. 7. // allocate triangular array 8. int[][] odds = new int[NMAX + 1][]; 9. for (int n = 0; n <= NMAX; n++) 10. odds[n] = new int[n + 1]; 11. 12. // fill triangular array 13. for (int n = 0; n < odds.length; n++) 14. for (int k = 0; k < odds[n].length; k++) 15. { 16. /* 17. compute binomial coefficient 18. n * (n - 1) * (n - 2) * . . . * (n - k + 1) 19. ------------------------------------------- 20. 1 * 2 * 3 * . . . * k 21. */ 22. int lotteryOdds = 1; 23. for (int i = 1; i <= k; i++) 24. lotteryOdds = lotteryOdds * (n - i + 1) / i; 25. 26. odds[n][k] = lotteryOdds; 27. } 28. 29. // print triangular array 30. for (int n = 0; n < odds.length; n++) 31. { 32. for (int k = 0; k < odds[n].length; k++) 33. { 34. // pad output with spaces 35. String output = " " + odds[n][k]; 36. // make output field 4 characters wide 37. output = output.substring(output.length() - 4); 38. System.out.print(output); 39. } 40. System.out.println(); 41. } 42. } 43. } 44.