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:

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:

  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.

Open table as spreadsheet

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:

Open table as spreadsheet

 

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:

Open table as spreadsheet

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:

10

This line declares a two-dimensional array that's used to store the possible moves for a knight in terms of x and y. For example, the knight's move of two squares left and one square up is represented as {−2, 1}. There are a total of eight possible moves, and each move has two values (x and y). So, this two-dimensional array has eight rows and two columns.

26

The code that gets the user's starting position for the knight and does all the calculations is complicated enough that I didn't want to include it in the main method, so I put it in a separate method named showNightMoves. That way, the do loop in the main method is kept simple. It just keeps going until the user enters N when getYorN is called.

31

The showNightMoves method begins here.

39

The board array represents the chessboard as a two-dimensional array with eight rows for the ranks and eight columns for the files. This array holds int values. A value of zero indicates that the square is empty. The square where the knight resides gets a 1, and any square the knight can move to gets a 2.

45

This do loop prompts the user for a valid square to plant the knight in. The loop includes a call to the method convertSquareToPos, which converts the user's entry (such as e4) to a Pos object. (The Pos class is defined later in the program; it represents a board position as an x, y pair.) This method returns null if the user enters an incorrect square, such as a9 or x4. So to get the user to enter a valid square, the loop just repeats if the converSquareToPos returns null.

52

The board position entered by the user is set to 1 to indicate the position of the knight.

59

A for loop is used to test all the possible moves for the knight to see if they're valid from the knight's current position using the moves array that was created way back in line 10. In the body of this loop, the calculateNewPos method is called. This method accepts a board position and x and y values to indicate where the knight can be moved. If the resulting move is legal, it returns a new Pos object that indicates the position the move leads to. If the move is not legal (that is, it takes the knight off the board), the calculateNewPos method returns null.

Assuming calculateNewPos returns a non-null value, the body of this loop then prints the square (it calls convertPosTosquare to convert the Pos object to a string, such as c3). Then it marks the board position represented by the move with a 2 to indicate that the knight can move to this square.

72

After all the moves are calculated, the printBoard method is called to print the board array.

78

This is the convertSquareToPos method. It uses a pair of brute-force if statements to convert a string such as a1 or e4 to a Pos object representing the same position. I could probably have made this method a little more elegant by converting the first letter in the string to a Char and then subtracting the offset of the letter a to convert the value to a proper integer. But I think the brute-force method is clearer, and requires only a few more lines of code.

Note that if the user enters an incorrect square (such as a9 or x2), null is returned.

114

This is the convertPosToSquare method, which does the opposite of the convertSquareToPos method. It accepts a Pos argument and returns a string that corresponds to the position. It uses a series of brute-force if statements to determine the letter that corresponds to the file, but does a simple addition to calculate the rank. (The Pos object uses array indexes for the y position, which start with zero. So 1 is added to get the rank numbers, which start with 1.)

134

The calculateNewPos method accepts a starting position, an x offset, and a y offset. It returns a new position if the move is legal; otherwise, it returns null. To find illegal moves, it adds the x and y offsets to the starting x and y position and checks to see if the result is less than zero or greater than 7. If the move is legal, it creates a new Pos object whose position is calculated by adding the x and y offsets to the x and y values of the starting position.

150

The printBoard method uses a nested for loop to print the board. The outer loop prints each rank. Notice that it indexes the array backwards, starting with 7 and going down to 0. That's necessary so that the first rank is printed at the bottom of the console output. An inner for loop is used to print the squares for each rank. In this loop, an if statement checks the value of the board array element that corresponds to the square to determine whether it prints an X, a question mark, or a hyphen.

167

The getYorN method simply displays a prompt on-screen and asks the user to enter Y or N. It returns true if the user enters Y, false if the user enters N. If the user enters anything else, this method prompts the user again.

183

The Pos class simply defines two public fields, x and y, to keep track of board positions. It also defines a constructor that accepts the x and y positions as parameters.

Open table as spreadsheet

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.

Table 2-1: Handy Methods of the Arrays Class

Open table as spreadsheet

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

21 16 100

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.

Категории