Chapter 2
IN THIS CHAPTER
Working with basic one-dimensional arrays
Using array initializers to set the initial values of an array
Using for loops with arrays
Working with two-dimensional arrays
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
.
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]
.
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:
x[5]
refers to an element of an array,
x
refers to the array itself.0
to
9
.length
field of the array variable.
x.length
, for example, returns the length of the array
x
.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.
int[] array1; // an array of int elements
int array2[]; // another array of int elements
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:
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 is initialized to an empty string.
String[] names = new String[10];
Here the array variable is declared and an array is created in one statement.
System.out.print("How many players? ");
int count = sc.nextInt(); // sc is a Scanner
String[] players = new String[count];
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.
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]);
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:
0
.for
loop closes all the lockers. This step isn’t really necessary because booleans initialize to
false
, but being explicit about initialization is good.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.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.!
) to reverse the setting of each locker. Thus, if the locker is open (
true
), it’s set to closed (
false
), and vice versa.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.)
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.
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.
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.
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.
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.
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
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
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.
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.
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++;
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 (
?
).
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;
}
}
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.showNightMoves
method begins here.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.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.
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 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.
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.)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.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.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.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.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 |
|
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
|
|
Returns an array that’s a copy of
|
|
Does basically what the
|
|
Returns
|
|
Returns
|
|
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. |
|
Fills the elements indicated by the
|
|
Sorts the array in ascending sequence. |
|
Sorts the specified elements of the array in ascending sequence. |
|
Formats the array values in a string. Each element value is enclosed in brackets, and the element values are separated with commas. |
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);
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.
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
→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
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);
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.");
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
.
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]