Chapter 2

Using Arrays

IN THIS CHAPTER

check Working with basic one-dimensional arrays

check Using array initializers to set the initial values of an array

check Using for loops with arrays

check Working with two-dimensional arrays

check Working with the Arrays class

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; multidimensional 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 is referenced by 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. An int array can contain int values, for example, 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 that 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 one instead of from zero. So, in Java, get used to counting from zero instead of from one.

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 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.

technicalstuff Just to make sure that you’re confused as much as possible, Java also lets you put the brackets on the variable name rather than on the type. The following two statements both create arrays of int elements:

int[] array1; // an array of int elements
int array2[]; // another array of int elements

tip Both of these statements have exactly the same effect. Most Java programmers prefer to put the brackets on the type rather than on 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. 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 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. Here’s a for loop that creates an array of 100 random numbers, with values ranging 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 that 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 a while, an array and a for loop or two can help you solve your kids’ homework problems for them. 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 that 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, and 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 that I’d made a mistake somewhere. And while I was looking at the code, 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:

  1. →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 0 .
  2. →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.
  3. →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.
  4. →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 n th locker on each trip through the hallways.
  5. →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.
  6. →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 that 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 it’s 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. 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.

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.

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 printString Array method as a parameter.

Using Two-Dimensional Arrays

The elements of an array can be any type of object you want, including another array. In the latter case, you have a two-dimensional array, sometimes called an array of arrays.

Two-dimensional arrays are often used to track data in column-and-row format, much the way that a spreadsheet works. Suppose that you’re working on a program that tracks five years’ worth of sales (2004 through 2008) 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 that 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:

Year

North

South

East

West

2004

23,853

22,838

36,483

31,352

2005

25,483

22,943

38,274

33,294

2006

24,872

23,049

39,002

36,888

2007

28,492

23,784

42,374

39,573

2008

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 . To put it another way, sales is an array of double arrays.

To 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. Then those five arrays are 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. This statement sets the 2004 sales for the North region:

sales[0][0] = 23853.0;

As you might imagine, accessing the data in a two-dimensional array by hardcoding each index value can get tedious. No wonder for loops are normally used instead. 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("\tNorth\t\tSouth\t\tEast\t\tWest");
int year = 2004;
for (int y = 0; y < 5; y++)
{
System.out.print(year + "\t");
for (int region = 0; region < 4; region++)
{
System.out.print(cf.format(sales[y][region]));
System.out.print("\t");
}
year++;
System.out.println();
}

Assuming that the sales array has already been initialized, this code produces the following output on the console:

North South East West
2004 $23,853.00 $22,838.00 $36,483.00 $31,352.00
2005 $25,483.00 $22,943.00 $38,274.00 $33,294.00
2006 $24,872.00 $23,049.00 $39,002.00 $36,888.00
2007 $28,492.00 $23,784.00 $42,374.00 $39,573.00
2008 $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 preceding example lists the sales for each year on a separate line, with the sales regions arranged in columns. 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}, // 2004
{25483.0, 22943.0, 38274.0, 33294.0}, // 2005
{24872.0, 23049.0, 39002.0, 36888.0}, // 2006
{28492.0, 23784.0, 42374.0, 39573.0}, // 2007
{31932.0, 23732.0, 42943.0, 41734.0} }; // 2008

Here I added a comment to the end of each line to show the year that 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. Java, however, 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.

Suppose that 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. 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

technicalstuff Java doesn’t limit you to 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 multidimensional 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. 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++;

Working with a Fun but Complicated Example: A Chessboard

Okay, so much for the business examples. Here’s an example that’s more fun — assuming 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 horsey, for the non-chess players among us), 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 each possible move indicated with a question mark ( ? ).

tip In case you’re not familiar with chess, it’s played on a board that’s 8 by 8 squares, 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 and 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 .

image

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 position: 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 . Also, the graphic representation of the board indicates where the knight is and where he can go.

LISTING 2-2 Playing Chess in a For Dummies Book

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.\n");
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("\nThe 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("\n" + 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;
}
}

technicalstuff You have to put your thinking cap on to make your way through this program, which is a bit on the complicated side. The following paragraphs can help clear up the more complicated lines:

  1. →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. The knight’s move of two squares left and one square up, for example, 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.
  2. →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.
  3. →31 The showNightMoves method begins here.
  4. →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 0 indicates that the square is empty. The square where the knight resides gets a 1, and any square that the knight can move to gets a 2.
  5. →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.
  6. →52 The board position entered by the user is set to 1 to indicate the position of the knight.
  7. →59 A for loop is used to test all the possible moves for the knight to see whether 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 that calculateNewPos returns a non-null value, the body of this loop 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 2 to indicate that the knight can move to this square.

  8. →72 After all the moves are calculated, the printBoard method is called to print the board array.
  9. →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 probably could 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 it 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.

  10. →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’s y member is an array for the y position. Array indexes are numbered starting with 0, but chess rank numbers start with 1. That’s why 1 is added to the y position to get the rank number.)
  11. →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 whether the result is less than 0 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.
  12. →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 backward, 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.
  13. →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 or false if the user enters N . If the user enters anything else, this method prompts the user again.
  14. →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.

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

Method

Description

static int binarySearch(array, key )

Searches for the specified key value in an array. The return value is the index of the element that matches the key. The method 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 checks equality only 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 in ascending sequence.

static void sort(array, from, to )

Sorts the specified elements of the array in 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 with commas.

Filling an array

The fill method can be handy if you want to prefill an array with values other than the default values for the array type. 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 evaluates this expression only once. Then it assigns the result of this expression to each element in the array.

You might think that 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 code 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. If you start with something named arrayOriginal , for example, 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

  1. →9 This is the line where you can change the number 3 to something smaller.

    You can do the following, for example:

    int arrayNew[] = Arrays.copyOf(arrayOriginal, 2 );

    If you do, 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. If you execute the instructions

    int arrayOriginal[] = {42, 55, 21, 16, 100, 88};
    int arrayNew[] = Arrays.copyOfRange(arrayOriginal, 2, 5);

    the values in arrayNew are

    21 16 100

Sorting an array

The sort method is a quick way to sort an array in sequence. These statements create an array with 100 random numbers and then sort the array in sequence so that 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. Suppose you want to find out whether your lucky number is in the lotto array created in the preceding example. You could just use a for loop, like this:

int lucky = 13x;
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.println("I'm not lucky today.");

Here the for loop compares each element in the array with your lucky number. This code 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 in 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.");

technicalstuff The binarySearch method uses a technique similar to the strategy for guessing a number. If I say that 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 works only if the array is sorted first.

Comparing arrays

If you use the equality operator ( == ) to compare array variables, the array variables are considered to be equal only if both variables point to exactly the 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 arrays array1 and array2 are compared element by element. If both arrays have the same number of elements, and all elements have the same value, the equals method returns true . If 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.

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]

tip 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.