Using Arrays
I could use a raise….
Oh, arrays. Sorry.
Arrays are an important aspect of any programming language, and Java is no exception. In this chapter, you discover just about everything you need to know about using arrays. I cover run-of-the-mill one-dimensional arrays, multi-dimensional arrays, and two classes that are used to work with arrays, named Array and Arrays.
Understanding Arrays
An array is a set of variables that are referenced using a single variable name combined with an index number. Each item of an array is called an element. All the elements in an array must be of the same type. Thus the array itself has a type that specifies what kind of elements it can contain. For example, an int array can contain int values, and a String array can contain strings.
The index number is written after the variable name and enclosed in brackets. So, if the variable name is x, you could access a specific element with an expression like x[5].
Tip |
You might think x[5] would refer to the fifth element in the array. But index numbers start with zero for the first element, so x[5] actually refers to the sixth element. This little detail is one of the chief causes of problems when working with arrays-especially if you cut your array-programming teeth in a language in which arrays are indexed from 1 instead of 0. So get used to counting from 0 instead of from 1. |
The real power of arrays comes from the simple fact that you can use a variable or even a complete expression as an array index. So (for example) instead of coding x[5] to refer to a specific array element, you can code x[i] to refer to the element indicated by the index variable i. You see plenty of examples of index variables throughout this chapter.
Here are a few additional tidbits of array information to ponder before you get into the details of creating and using arrays:
- An array is itself an object. You can refer to the array object as a whole rather than a specific element of the array by using the array's variable name without an index. Thus, if x[5] refers to an element of an array, x refers to the array itself.
- An array has a fixed length that's set when the array is created. This length determines the number of elements that can be stored in the array. The maximum index value you can use with any array is one less than the array's length. Thus, if you create an array of ten elements, you can use index values from 0 to 9.
- You can't change the length of an array after you create the array.
- You can access the length of an array by using the length field of the array variable. For example, x.length returns the length of the array x.
Creating Arrays
Before you can create an array, you must first declare a variable that refers to the array. This variable declaration should indicate the type of elements that are stored by the array followed by a set of empty brackets, like this:
String[] names;
Here a variable named names is declared. Its type is an array of String objects.
TECHNICAL STAUFF |
Just to make sure you're confused as much as possible, Java also lets you put the brackets on the variable name rather than the type. For example, the following two statements both create arrays of int elements: int[] array1; // an array of int elements int array2[]; // another array of int elements |
Both of these statements have exactly the same effect. Most Java programmers prefer to put the brackets on the type rather than the variable name.
By itself, that statement doesn't create an array. It merely declares a variable that can refer to an array. You can actually create the array in two ways:
- Use the new keyword followed by the array type, this time with the brackets filled in to indicate how many elements the array can hold. For example:
String[] names; names = new String[10];
Here, an array of String objects that can hold ten strings is created. Each of the strings in this array are initialized to an empty string.
- As with any other variable, you can combine the declaration and the creation into one statement:
String[] names = new String[10];
Here, the array variable is declared, and an array is created in one statement.
Tip |
If you don't know how many elements the array needs at compile time, you can use a variable or an expression for the array length. For example, here's a routine from a method that stores player names in an array of strings. It starts by asking the user how many players are on the team. Then it creates an array of the correct size: System.out.print("How many players? "); int count = sc.nextInt(); // sc is a Scanner String[] players = new String[count]; |
Initializing an Array
One way to initialize the values in an array is to simply assign them one by one:
String[] days = new Array[7]; Days[0] = "Sunday"; Days[1] = "Monday"; Days[2] = "Tuesday"; Days[3] = "Wednesday"; Days[4] = "Thursday"; Days[5] = "Friday"; Days[6] = "Saturday";
Java has a shorthand way to create an array and initialize it with constant values:
String[] days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
Here each element to be assigned to the array is listed in an array initializer. Here's an example of an array initializer for an int array:
int[] primes = { 2, 3, 5, 7, 11, 13, 17 };
Note |
The length of an array created with an initializer is determined by the number of values listed in the initializer. |
An alternative way to code an initializer is like this:
int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17 };
To use this type of initializer, you use the new keyword followed by the array type and a set of empty brackets. Then you code the initializer.
Using for Loops with Arrays
One of the most common ways to process an array is with a for loop. In fact, for loops were invented specifically to deal with arrays. For example, here's a for loop that creates an array of 100 random numbers, with values from 1 to 100:
int[] numbers = new int[100]; for (int i = 0; i < 100; i++) numbers[i] = (int)(Math.random() * 100) + 1;
And here's a loop that fills an array of player names with strings entered by the user:
String[] players = new String[count]; for (int i = 0; i < count; i++) { System.out.print("Enter player name: "); players[i] = sc.nextLine(); // sc is a Scanner }
For this example, assume count is an int variable that holds the number of players to enter.
You can also use a for loop to print the contents of an array. For example:
for (int i = 0; i < count; i++) System.out.println(players[i]);
Here the elements of a String array named players are printed to the console.
The previous example assumes that the length of the array was stored in a variable before the loop was executed. If you don't have the array length handy, you can get it from the array's length property:
for (int i = 0; i < players.length; i++) System.out.println(players[i]);
Solving Homework Problems with Arrays
Every once in awhile, an array and a for loop or two can help you solve your kids' homework problems for them. For example, I once helped my daughter solve a tough homework assignment for a seventh grade math class. The problem was stated something like this:
Bobo (these problems always had a character named Bobo in them) visits the local high school on a Saturday and finds that all the school's 1,000 lockers are neatly closed. So he starts at one end of the school and opens them all. Then he goes back to the start and closes every other locker (lockers 2, 4, 6, and so on). Then he goes back to the start and hits every third locker: If it's open, he closes it. If it's closed, he opens it. Then he hits every fourth locker, every fifth locker, and so on. He keeps doing this all weekend long, walking the hallways opening and closing lockers 1,000 times. Then he gets bored and goes home. How many of the school's 1,000 lockers are left open, and which ones are they?
Sheesh!
This problem presented a challenge, and being the computer-nerd father I am, I figured this was the time to teach my daughter about for loops and arrays. So I wrote a little program that set up an array of 1,000 booleans. Each represented a locker: true meant open, false meant closed. Then I wrote a pair of nested for loops to do the calculation.
My first attempt told me that 10,000 of the 1,000 lockers were opened, so I figured I had made a mistake somewhere. And while I was looking at it, I realized that the lockers were numbered 1 to 1,000, but the elements in my array were numbered 0 to 999, and that was part of what led to the confusion that caused my first answer to be ridiculous.
So I decided to create the array with 1,001 elements and ignore the first one. That way the indexes corresponded nicely to the locker numbers.
After a few hours of work, I came up with the program in Listing 2-1.
Listing 2-1: The Classic Locker Problem Solved!
public class BoboAndTheLockers { public static void main(String[] args) { // true = open; false = closed boolean[] lockers = new boolean[1001]; → 6 // close all the lockers for (int i = 1; i <= 1000; i++) → 9 lockers[i] = false; for (int skip = 1; skip <= 1000; skip++)→ 12 { System.out.println("Bobo is changing every " + skip + " lockers."); for (int locker = skip; locker < 1000; → 16 locker += skip) lockers[locker] = !lockers[locker]; → 18 } System.out.println("Bobo is bored" + " now so he's going home."); // count and list the open lockers String list = ""; int openCount = 0; for (int i = 1; i <= 1000; i++) → 27 if (lockers[i]) { openCount++; list += i + " "; } System.out.println("Bobo left " + openCount + " lockers open."); System.out.println("The open lockers are: " + list); } }
Here are the highlights of how this program works:
→ 6 |
This line sets up an array of booleans with 1,001 elements. I created one more element than I needed so I could ignore element zero. |
→ 9 |
This for loop closes all the lockers. This step isn't really necessary, because booleans initialize to false. But being explicit about initialization is good. |
→ 12 |
Every iteration of this loop represents one complete trip through the hallways opening and closing lockers. The skip variable represents how many lockers Bobo skips on each trip. First he does every locker, then every second locker, and then every third locker. So this loop simply counts from 1 to 1,000. |
→ 16 |
Every iteration of this loop represents one stop at a locker on a trip through the hallways. This third expression in the for statement (on the next line) adds the skip variable to the index variable so that Bobo can access every nth locker on each trip through the hallways. |
→ 18 |
This statement uses the not operator (!) to reverse the setting of each locker. Thus, if the locker is open (true), it's set to closed (false). And vice versa. |
→ 27 |
Yet another for loop spins through all the lockers and counts the ones that are open. It also adds the locker number for each open locker to the end of a string so all the open lockers can be printed. |
This program produces more than 1,000 lines of output. But only the last few lines are important. Here they are:
Bobo is bored now so he's going home. Bobo left 31 lockers open. The open lockers are: 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900 961
So there's the answer: 31 lockers are left open. I got an A. (I mean, my daughter got an A.)
Tip |
By the way, did you notice that the lockers that were left open were the ones whose numbers are perfect squares? Or that 31 is the largest number whose square is less than 1,000? I didn't either, until my daughter told me after school the next day. |
Using the Enhanced for Loop
Java 1.5 introduced a new type of for loop called an enhanced for loop that's designed to simplify loops that process arrays and collections (which I cover in the next chapter). When used with an array, the enhanced for loop has this format:
for (type identifier: array) { statements... }
The type identifies the type of the elements in the array, and the identifier provides a name for a local variable that is used to access each element. And array names the array you want to process.
Here's an example:
String[] days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; for (String day: days) { System.out.println(day); }
This loop prints the following lines to the console:
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
In other words, it prints each of the strings in the array on a separate line.
REMEMBER |
The enhanced for loop was a new feature for Java 1.5, so you can't use it if you're working with an earlier version. |
Using Arrays with Methods
You can write methods that accept arrays as parameters and return arrays as return values. You just use an empty set of brackets to indicate that the parameter type or return type is an array.
For example, here's a static method that creates and returns a String array with the names of the days of the week:
public static String[] getDaysOfWeek() { String[] days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; return days; }
And here's a static method that prints the contents of any String array to the console, one string per line:
public static void printStringArray(String[] strings) { for (String s: strings) System.out.println(s); }
Finally, here are two lines of code that call these methods:
String[] days = getDaysOfWeek(); printStringArray(days);
The first statement declares a String array, and then calls getDaysOfWeek to create the array. The second statement passes the array to the printStringArray method as a parameter.
Using Two Dimensional Arrays
The elements of an array can be any type of object you want, including another array. This is called a two-dimensional array or, sometimes, an array of arrays.
Two-dimensional arrays are often used to track data in a column and row format, much the way a spreadsheet works. For example, suppose you're working on a program that tracks five years' worth of sales (2001 through 2005) for a company, with the data broken down for each of four sales territories (North, South, East, and West). You could create 20 separate variables, with names such as sales2001North, sales2001South, sales2001East, and so on. But that gets a little tedious.
Alternatively, you could create an array with 20 elements, like this:
double[] sales = new sales[20];
But then, how would you organize the data in this array so you know the year and sales region for each element?
With a two-dimensional array, you can create an array with an element for each year. Each of those elements, in turn, is another array with an element for each region.
Thinking of a two-dimensional array as a table or spreadsheet is common, like this:
North |
South |
East |
West |
|
---|---|---|---|---|
2001 |
23,853 |
22,838 |
36,483 |
31,352 |
2002 |
25,483 |
22,943 |
38,274 |
33,294 |
2003 |
24,872 |
23,049 |
39,002 |
36,888 |
2004 |
28,492 |
23,784 |
42,374 |
39,573 |
2005 |
31,932 |
23,732 |
42,943 |
41,734 |
Here each row of the spreadsheet represents a year of sales, and each column represents one of the four sales regions.
Creating a two dimensional array
To declare a two-dimensional array for this sales data, you simply list two sets of empty brackets, like this:
double sales[][];
Here sales is a two-dimensional array of type double. Or, to put it another way, sales is an array of double arrays.
To actually create the array, you use the new keyword and provide lengths for each set of brackets, as in this example:
sales = new double[5][4];
Here the first dimension specifies that the sales array has five elements. This array represents the rows in the table. The second dimension specifies that each of those elements has an array of type double with four elements. This array represents the columns in the table.
Tip |
A key point to grasp here is that one instance is of the first array, but a separate instance of the second array for each element is in the first array. So this statement actually creates five double arrays with four elements each. Those five arrays are then used as the elements for the first array. |
Note that as with a one-dimensional array, you can declare and create a two-dimensional array in one statement, like this:
double[][] sales = new double[5][4];
Here the sales array is declared and created all in one statement.
Accessing two dimensional array elements
To access the elements of a two-dimensional array, you use two indexes. For example, this statement sets the 2001 sales for the North region:
sales[0][0] = 23853.0;
As you might imagine, accessing the data in a two-dimensional array by hard-coding each index value can get tedious. No wonder for loops are normally used instead. For example, the following bit of code uses a for loop to print the contents of the sales array to the console, separated by tabs. Each year is printed on a separate line, with the year at the beginning of the line. In addition, a line of headings for the sales regions is printed before the sales data. Here's the code:
NumberFormat cf = NumberFormat.getCurrencyInstance(); System.out.println(" North South East West"); int year = 2001; for (int y = 0; y < 5; y++) { System.out.print(year + " "); for (int region = 0; region < 4; region++) { System.out.print(cf.format(sales[y][region])); System.out.print(" "); } year++; System.out.println(); }
Assuming the sales array has already been initialized, this code produces the following output on the console:
North South East West 2001 $23,853.00 $22,838.00 $36,483.00 $31,352.00 2002 $25,483.00 $22,943.00 $38,274.00 $33,294.00 2003 $24,872.00 $23,049.00 $39,002.00 $36,888.00 2004 $28,492.00 $23,784.00 $42,374.00 $39,573.00 2005 $31,932.00 $23,732.00 $42,943.00 $41,734.00
Warning |
The order in which you nest the for loops that access each index in a two-dimensional array is crucial! The previous example lists the sales for each year on a separate line, with the sales regions arranged in columns. For example, you can print a listing with the sales for each region on a separate line, with the years arranged in columns by reversing the order in which the for loops that index the arrays are nested: for (int region = 0; region < 4; region++) { for (int y = 0; y < 5; y++) { System.out.print(cf.format(sales[y][region])); System.out.print(" "); } System.out.println(); } |
Here the outer loop indexes the region, and the inner loop indexes the year.
$23,853.00 $25,483.00 $24,872.00 $28,492.00 $31,932.00 $22,838.00 $22,943.00 $23,049.00 $23,784.00 $23,732.00 $36,483.00 $38,274.00 $39,002.00 $42,374.00 $42,943.00 $31,352.00 $33,294.00 $36,888.00 $39,573.00 $41,734.00
Initializing a two dimensional array
The technique for initializing arrays by coding the array element values in curly braces works for two-dimensional arrays too. You just have to remember that each element of the main array is actually another array. So, you have to nest the array initializers.
Here's an example that initializes the sales array:
double[][] sales = { {23853.0, 22838.0, 36483.0, 31352.0}, // 2001 {25483.0, 22943.0, 38274.0, 33294.0}, // 2002 {24872.0, 23049.0, 39002.0, 36888.0}, // 2003 {28492.0, 23784.0, 42374.0, 39573.0}, // 2004 {31932.0, 23732.0, 42943.0, 41734.0} }; // 2005
Here I added a comment to the end of each line to show the year the line initializes. Notice that the left brace for the entire initializer is at the beginning of the second line, and the right brace that closes the entire initializer is at the end of the last line. Then the initializer for each year is contained in its own set of braces.
Using jagged arrays
When you create an array with an expression such as new int[5][3], you're specifying that each element of the main array is actually an array of type int with three elements. However, Java lets you create two-dimensional arrays in which the length of each element of the main array is different. This is sometimes called a jagged array because the array doesn't form a nice rectangle. Instead, its edges are jagged.
For example, suppose you need to keep track of four teams, each consisting of two or three people. The teams are as follows:
Team |
Members |
---|---|
A |
Henry Blake, Johnny Mulcahy |
B |
Benjamin Pierce, John McIntyre, Jonathan Tuttle |
C |
Margaret Houlihan, Frank Burns |
D |
Max Klinger, Radar O'Reilly, Igor Straminsky |
The following code creates a jagged array for these teams:
String[][] teams = { {"Henry Blake", "Johnny Mulcahy"}, {"Benjamin Pierce", "John McIntyre", "Jonathan Tuttle"}, {"Margaret Houlihan", "Frank Burns"}, {"Max Klinger", "Radar O'Reilly", "Igor Straminsky"} };
Here each nested array initializer indicates the number of strings for each subarray. For example, the first subarray has two strings, the second has three strings, and so on.
You can use nested for loops to access the individual elements in a jagged array. For each element of the main array, you can use the length property to determine how many entries are in that element's subarray. For example:
for (int i = 0; i < teams.length; i++) { for (int j = 0; j < teams[i].length; j++) System.out.println(teams[i][j]); System.out.println(); }
Notice that the length of each subarray is determined with the expression teams[i].length. This for loop prints one name on each line, with a blank line between teams, like this:
Margaret Houlihan Frank Burns Max Klinger Radar O'Reilly Igor Straminsky Henry Blake Johnny Mulcahy Benjamin Pierce John McIntyre Jonathan Tuttle
If you don't want to fuss with keeping track of the indexes yourself, you can use an enhanced for loop and let Java take care of the indexes. For example:
for (String[] team: teams) { for (String player: team) System.out.println(player); System.out.println(); }
Here the first enhanced for statement specifies that the type for the team variable is String[]. As a result, each cycle of this loop sets team to one of the subarrays in the main teams array. Then the second enhanced for loop accesses the individual strings in each subarray.
Going beyond two dimensions
TECHNICAL STAUFF |
Java doesn't limit you to just two-dimensional arrays. Arrays can be nested within arrays to as many levels as your program needs. To declare an array with more than two dimensions, you just specify as many sets of empty brackets as you need. For example: int[][][] threeD = new int[3][3][3]; |
Here a three-dimensional array is created, with each dimension having three elements. You can think of this array as a cube. Each element requires three indexes to access.
You can access an element in a multi-dimensional array by specifying as many indexes as the array needs. For example:
threeD[0][1][2] = 100;
This statement sets element 2 in column 1 of row 0 to 100.
You can nest initializers as deep as necessary, too. For example:
int[][][] threeD = { { {1, 2, 3}, { 4, 5, 6}, { 7, 8, 9} }, { {10, 11, 12}, {13, 14, 15}, {16, 17, 18} }, { {19, 20, 21}, {22, 23, 24}, {25, 26, 27} } };
Here a three-dimensional array is initialized with the numbers 1 through 27.
You can also use multiple nested if statements to process an array with three or more dimensions. For example, here's another way to initialize a three-dimensional array with the numbers 1 to 27:
int[][][] threeD2 = new int[3][3][3]; int value = 1; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) threeD2[i][j][k] = value++;
A Fun but Complicated Example A Chessboard
Okay, so much for the business examples. Here's an example that's more fun, at least if you think chess is fun. The program in Listing 2-2 uses a two-dimensional array to represent a chessboard. Its sole purpose is to figure out the possible moves for a knight (that's the horse for those of you in Rio Linda) given its starting position. The user is asked to enter a starting position (such as f1), and the program responds by displaying the possible squares. Then the program prints out a crude but recognizable representation of the board with the knight's position indicated with an X and his possible moves indicated with question marks.
Tip |
In case you're not familiar with chess, it's played on a board that's 8 x 8, with alternating light and dark squares. The normal way to identify each square is to use a letter and a number, where the letter represents the column (called a file) and the number represents the row (called a rank), as shown in Figure 2-1. The knight has an interesting movement pattern: He moves two squares in one direction, then makes a 90-degree turn and moves one square to the left or right. The possible moves for the knight given a starting position of e4 are shaded dark. As you can see, this knight has eight possible moves: c3, c5, d6, f6, g5, g3, f2, and d2. |
Figure 2-1: A classic chessboard.
Here's a sample of what the console looks like if you enter e4 for the knight's position:
Welcome to the Knight Move calculator. Enter knight's e4 The knight is at square e4 From here the knight can move to: c5 d6 f6 g5 g3 f2 d2 c3 - - - - - - - - - - - - - - - - - - - ? - ? - - - - ? - - - ? - - - - - X - - - - - ? - - - ? - - - - ? - ? - - - - - - - - - - Do it again? (Y or N) n
As you can see, the program indicates that the knight's legal moves from e4 are c5, d6, f6, g5, g3, f2, d2, and c3. And the graphic representation of the board indicates where the knight is and where he can go.
Listing 2-2: Playing Chess in a For DummiesBook?
import java.util.Scanner; public class KnightMoves { static Scanner sc = new Scanner(System.in); // the following static array represents the 8 // possible moves a knight can make // this is an 8 x 2 array static int[][] moves = { {-2, +1}, → 10 {-1, +2}, {+1, +2}, {+2, +1}, {+2, -1}, {+1, -2}, {-1, -2}, {-2, -1} }; public static void main(String[] args) { System.out.println("Welcome to the " + "Knight Move calculator. "); do { showKnightMoves(); → 26 } while (getYorN("Do it again?")); } public static void showKnightMoves() → 31 { // The first dimension is the file (a, b, c, etc.) // The second dimension is the rank (1, 2, 3, etc.) // Thus, board[3][4] is square d5. // A value of 0 means the square is empty // 1 means the knight is in the square // 2 means the knight could move to the square int[][] board = new int[8][8]; → 39 String kSquare; // the knight's position as a square Pos kPos; // the knight's position as a Pos // get the knight's initial position do → 45 { System.out.print("Enter knight's position: "); kSquare = sc.nextLine(); kPos = convertSquareToPos(kSquare); } while (kPos == null); board[kPos.x][kPos.y] = 1; → 52 System.out.println(" The knight is at square " + convertPosToSquare(kPos)); System.out.println( "From here the knight can move to:"); for (int move = 0; move < moves.length; move ++) → 59 { int x, y; x = moves[move][0]; // the x for this move y = moves[move][1]; // the y for this move Pos p = calculateNewPos(kPos, x, y); if (p != null) { System.out.println(convertPosToSquare(p)); board[p.x][p.y] = 2; } } printBoard(board); → 72 } // this method converts squares such as a1 or d5 to // x, y coordinates such as [0][0] or [3][4] public static Pos convertSquareToPos(String square) → 78 { int x = -1; int y = -1; char rank, file; file = square.charAt(0); if (file == 'a') x = 0; if (file == 'b') x = 1; if (file == 'c') x = 2; if (file == 'd') x = 3; if (file == 'e') x = 4; if (file == 'f') x = 5; if (file == 'g') x = 6; if (file == 'h') x = 7; rank = square.charAt(1); if (rank == '1') y = 0; if (rank == '2') y = 1; if (rank == '3') y = 2; if (rank == '4') y = 3; if (rank == '5') y = 4; if (rank == '6') y = 5; if (rank == '7') y = 6; if (rank == '8') y = 7; if (x == -1 || y == -1) { return null; } else return new Pos(x, y); } // this method converts x, y coordinates such as // [0][0] or [3][4] to squares such as a1 or d5. public static String convertPosToSquare(Pos p) → 114 { String file = ""; if (p.x == 0) file = "a"; if (p.x == 1) file = "b"; if (p.x == 2) file = "c"; if (p.x == 3) file = "d"; if (p.x == 4) file = "e"; if (p.x == 5) file = "f"; if (p.x == 6) file = "g"; if (p.x == 7) file = "h"; return file + (p.y + 1); } // this method calculates a new Pos given a // starting Pos, an x move, and a y move // it returns null if the resulting move would // be off the board. public static Pos calculateNewPos(Pos p, int x, int y) → 134 { // rule out legal moves if (p.x + x < 0) return null; if (p.x + x > 7) return null; if (p.y + y < 0) return null; if (p.y + y > 7) return null; // return new position return new Pos(p.x + x, p.y + y); } public static void printBoard(int[][] b) → 150 { for (int y = 7; y >= 0; y--) { for (int x = 0; x < 8; x++) { if (b[x][y] == 1) System.out.print(" X "); else if (b[x][y] == 2) System.out.print(" ? "); else System.out.print(" - "); } System.out.println(); } } public static boolean getYorN(String prompt) → 167 { while (true) { String answer; System.out.print(" " + prompt + " (Y or N) "); answer = sc.nextLine(); if (answer.equalsIgnoreCase("Y")) return true; else if (answer.equalsIgnoreCase("N")) return false; } } } // this class represents x, y coordinates on the board class Pos → 183 { public int x; public int y; public Pos(int x, int y) { this.x = x; this.y = y; } }
TECHNICAL STAUFF |
You have to put your thinking cap on to follow your way through this program. It's a bit on the complicated side. The following paragraphs can help clear up the more complicated lines:
|
Using the Arrays Class
The final topic for this chapter is the Arrays class, which provides a collection of static methods that are useful for working with arrays. The Arrays class is in the java.util package, so you have to use an import statement for the java.util.Arrays class or the entire java.util.* package to use this class. Table 2-1 lists the most commonly used methods of the Arrays class.
Method |
Description |
---|---|
static int binarySearch(array |
Searches for the specified key value in an, key) array. The return value is the index of the element that matches the key. Returns −1 if the key couldn't be found. The array and the key must be of the same type and can be any primitive type or an object. |
static array copyOf(arrayOriginal, newLength) |
Returns an array that's a copy of arrayOriginal. The newLength parameter need not equal the original array's length. If newLength is larger, the method pads the new array with zeros. If newLength is smaller, the method doesn't copy all of the original array's values. |
static array copyOfRange(arrayOriginal, from, to |
Does basically what the copyOf method does, but copies only a selected slice of values ) (from one index to another) of the original array. |
boolean deepEquals( array1, array2 |
Returns true if the two arrays have the same ) element values. This method works for arrays of two or more dimensions. |
boolean equals( array1, array2 |
Returns true if the two arrays have the same ) element values. This method only checks equality for one-dimensional arrays. |
static void fill(array, value) |
Fills the array with the specified value. The value and array must be of the same type and can be any primitive type or an object. |
static void fill(array, from, to, value) |
Fills the elements indicated by the from and to int parameters with the specified value. The value and array must be of the same type and can be any primitive type or an object. |
static void sort(array) |
Sorts the array into ascending sequence. |
static void sort(array, from, to) |
Sorts the specified elements of the array into ascending sequence. |
static String toString(array) |
Formats the array values in a string. Each element value is enclosed in brackets, and the element values are separated from each other with commas. |
Filling an array
The fill method can be handy if you want to pre-fill an array with values other than the default values for the array type. For example, here's a routine that creates an array of integers and initializes each element to 100:
int[] startValues = new int[10]; Arrays.fill(startValues, 100);
Warning |
Although you can code a complicated expression as the second parameter, the fill method only evaluates this expression once. Then it assigns the result of this expression to each element in the array. |
For example, you might think you could fill an array of 1,000 integers with random numbers from 1 to 100 like this:
int[] ran = new int[1000] Arrays.fill(ran, (int)(Math.random() * 100) + 1);
Unfortunately, this won't work. What happens is that the expression is evaluated once to get a random number. Then all 1,000 elements in the array are set to that random number.
Copying an array
In Java 1.6, the Arrays class has some useful new methods. Using the new copyOf and copyOfRange methods, you can copy a bunch of elements from an existing array into a brand-new array. For example, if you start with something named arrayOriginal, you can copy the arrayOriginal elements to something named arrayNew as shown in Listing 2-3.
Listing 2-3: The Copycat
import java.util.Arrays; class CopyDemo { public static void main(String args[]) { int arrayOriginal[] = {42, 55, 21}; int arrayNew[] = Arrays.copyOf(arrayOriginal, 3); →9 printIntArray(arrayNew); } static void printIntArray(int arrayNew[]) { for (int i : arrayNew) { System.out.print(i); System.out.print(' '); } System.out.println(); } }
The output of the CopyDemo program looks like this:
42 55 21
→ 9 |
This is the line where you can change the number 3 to something smaller. |
For example, you do the following:
int arrayNew[] = Arrays.copyOf(arrayOriginal, 2);
If you do, then arrayNew has fewer than three elements:
42 55
You can also change the number 3 to something larger:
int arrayNew[] = Arrays.copyOf(arrayOriginal, 8);
Then arrayNew has more than three elements:
42 55 21 0 0 0 0 0
The copyOfRange method is even more versatile. For example, execute the following instructions
int arrayOriginal[] = {42, 55, 21, 16, 100, 88}; int arrayNew[] = Arrays.copyOfRange(arrayOriginal, 2, 5);
Then the values in arrayNew are
Sorting an array
The sort method is a quick way to sort an array into sequence. For example, these statements create an array with 100 random numbers, and then sort the array into sequence so the random numbers are in order:
int[] lotto = new int[6]; for (int i = 0; i < 6; i++) lotto[i] = (int)(Math.random() * 100) + 1; Arrays.sort(lotto);
Searching an array
The binarySearch method is an efficient way to locate an item in an array by its value. For example, suppose you want to find out if your lucky number is in the lotto array created in the previous example. You could just use a for loop, like this:
int lucky = 13; int foundAt = -1; for (int i = 0; i < lotto.length; i++) if (lotto[i] == lucky) foundAt = i; if (foundAt > -1) System.out.println("My number came up!"); else System.out.out.println("I'm not lucky today.");
Here the for loop compares each element in the array with my lucky number. This works fine for small arrays, but what if the array had 1,000,000 elements instead of 6? In that case, it would take a while to look at each element. If the array is sorted into sequence, the binarySearch method can find your lucky number more efficiently and with less code:
int lucky = 13; int foundAt = Arrays.binarySearch(lotto, lucky); if (foundAt > -1) System.out.println("My number came up!"); else System.out.println("I'm not lucky today.");
TECHNICAL STAUFF |
The binarySearch method uses a technique similar to the strategy for guessing a number. If I say I'm thinking of a number between 1 and 100, you don't start guessing the numbers in sequence starting with 1. Instead, you guess 50. If I tell you that 50 is low, you guess 75. Then, if I tell you 75 is high, you guess halfway between 50 and 75. And so on until you find the number. The binarySearch method uses a similar technique, but it only works if the array is sorted first. |
Comparing arrays
If you use the equality operator (==) to compare array variables, the array variables are considered equal only if both variables point to the exact same array instance. To compare two arrays element by element, you should use the Arrays.equal method instead. For example:
if (Arrays.equal(array1, array2)) System.out.println("The arrays are equal!");
Here the two arrays array1 and array2 are compared element by element. If both arrays have the same number of elements and each element has the same value, the equals method returns true. If any of the elements are not equal, or if one array has more elements than the other, the equals method returns false.
Tip |
If the array has more than one dimension, you can use the deepEquals method instead. It compares any two subarrays, element by element, to determine whether they're identical. |
Converting arrays to strings
The toString method of the Arrays class is handy if you want to quickly dump the contents of an array to the console to see what it contains. This method returns a string that shows the array's elements enclosed in brackets, with the elements separated by commas.
For example, here's a routine that creates an array, fills it with random numbers, and then uses the toString method to print the array elements:
int[] lotto = new int[6]; for (int i = 0; i < 6; i++) lotto[i] = (int)(Math.random() * 100) + 1; System.out.println(Arrays.toString(lotto));
Here's a sample of the console output created by this code:
[4, 90, 65, 84, 99, 81]
Note that the toString method works only for one-dimensional arrays. To print the contents of a two-dimensional array with the toString method, use a for loop to call the toString method for each subarray.