Chapter 4. Lists, Logic, and Loops

Today, you learn about three of the most boring features in the Java language:

  • How to make part of a Java program repeat itself by using loops

  • How to make a program decide whether to do something based on logic

  • How to organize groups of the same class or data type into lists called arrays

If these features don’t sound boring to you, they shouldn’t. Most of the significant work that you will accomplish with your Java software will use all three.

These topics are boring for computers because they enable software to do one of the things at which it excels: performing repetitive tasks over and over.

Arrays

At this point, you have dealt with only a few variables in each Java program. In some cases, it’s manageable to use individual variables to store information, but what if you had 20 items of related information to track? You could create 20 different variables and set up their initial values, but that approach becomes progressively more cumbersome as you deal with larger amounts of information. What if there were 100 items, or even 1,000?

Arrays are a way to store a list of items that have the same primitive data type, the same class, or a common parent class. Each item on the list goes into its own numbered slot so that you can easily access the information.

Arrays can contain any type of information that is stored in a variable, but after the array is created, you can use it for that information type only. For example, you can have an array of integers, an array of String objects, or an array of arrays, but you can’t have an array that contains both String objects and integers.

Java implements arrays differently than some other languages do—as objects treated like other objects.

To create an array in Java, you must do the following:

  1. Declare a variable to hold the array.

  2. Create a new array object and assign it to the array variable.

  3. Store information in that array.

Declaring Array Variables

The first step in array creation is to declare a variable that will hold the array. Array variables indicate the object or data type that the array will hold and the name of the array. To differentiate from regular variable declarations, a pair of empty brackets ([]) is added to the object or data type, or to the variable name.

The following statements are examples of array variable declarations:

String[] requests;

Point[] targets;

float[] donations;

You also can declare an array by putting the brackets after the variable name instead of the information type, as in the following statements:

String requests[];

Point targets[];

float donations[];

Note

The choice of which style to use is a matter of personal preference. The sample programs in this book place the brackets after the information type rather than the variable name, which is the more popular convention among Java programmers.

Creating Array Objects

After you declare the array variable, the next step is to create an array object and assign it to that variable. To do this:

  • Use the new operator.

  • Initialize the contents of the array directly.

Because arrays are objects in Java, you can use the new operator to create a new instance of an array, as in the following statement:

String[] players = new String[10];

This statement creates a new array of strings with 10 slots that can contain String objects. When you create an array object by using new, you must indicate how many slots the array will hold. This statement does not put actual String objects in the slots; you must do that later.

Array objects can contain primitive types, such as integers or Booleans, just as they can contain objects:

int[] temps = new int[99];

When you create an array object using new, all its slots automatically are given an initial value (0 for numeric arrays, false for Booleans, ‘’ for character arrays, and null for objects).

Note

The Java keyword null refers to a null object (and can be used for any object reference). It is not equivalent to zero or the '' character as the NULL constant is in C.

Because each object in an array of objects has a null reference when created, you must assign an object to each array element before using it.

The following example creates an array of three Integer objects and then assigns each element an object:

Integer[] series = new Integer[3];
series[0] = new Integer(10);
series[1] = new Integer(3);
series[2] = new Integer(5);

You can create and initialize an array at the same time by enclosing the elements of the array inside braces, separated by commas:

Point[] markup = { new Point(1,5), new Point(3,3), new Point(2,3) };

Each of the elements inside the braces must be the same type as the variable that holds the array. When you create an array with initial values in this manner, the array will be the same size as the number of elements you include within the braces. The preceding example creates an array of Point objects named markup that contains three elements.

Because String objects can be created and initialized without the new operator, you can do the same when creating an array of strings:

String[] titles = { "Mr.", "Mrs.", "Ms.", "Miss", "Dr." };

The preceding statement creates a five-element array of String objects named titles.

All arrays have an instance variable named length that contains the number of elements in the array. Extending the preceding example, the variable titles.length contains the value 5.

Accessing Array Elements

After you have an array with initial values, you can retrieve, change, and test the values in each slot of that array. The value in a slot is accessed with the array name followed by a subscript enclosed within square brackets. This name and subscript can be put into expressions, as in the following:

testScore[40] = 920;

The first element of an array has a subscript of 0 rather than 1, so an array with 12 elements has array slots accessed by using subscripts 0 through 11.

The preceding statement sets the 41st element of the testScore array to a value of 920. The testScore part of this expression is a variable holding an array object, although it also can be an expression that results in an array. The subscript expression specifies the slot to access within the array.

All array subscripts are checked to make sure that they are inside the array’s boundaries as specified when the array was created. In Java, it is impossible to access or assign a value to an array slot outside the array’s boundaries, avoiding problems that result from overrunning the bounds of an array in C-type languages. Note the following two statements:

float[] rating = new float[20];
rating[20] = 3.22F;

A program with the preceding two lines of code produces a compilation error when rating[20] is used in a statement. The error occurs because the rating array does not have a slot 20; it has 20 slots that begin at 0 and end at 19. The Java compiler would make note of this by stopping with an ArrayIndexOutOfBoundsException error.

The Java interpreter also notes an error if the array subscript is calculated when the program is running and the subscript is outside the array’s boundaries. You learn more about errors, which are called exceptions, on Day 7, “Exceptions, Assertions, and Threads.”

One way to avoid accidentally overrunning the end of an array in your programs is to use the length instance variable. The following statement displays the number of elements in the rating object:

System.out.println("Elements: " + rating.length);

Changing Array Elements

As you saw in the previous examples, you can assign a value to a specific slot in an array by putting an assignment statement after the array name and subscript, as in the following:

temperature[4] = 85;

day[0] = "Sunday";

manager[2] = manager[0];

An important thing to note is that an array of objects in Java is an array of references to those objects. When you assign a value to a slot in that kind of array, you are creating a reference to that object. When you move values around inside arrays, you are reassigning the reference rather than copying a value from one slot to another. Arrays of a primitive data type, such as int or float, do copy the values from one slot to another, as do elements of a String array, even though they are objects.

Arrays are reasonably simple to create and modify, and they provide an enormous amount of functionality for Java. Listing 4.1 shows a simple program that creates, initializes, and displays elements of three arrays.

Example 4.1. The Full Text of HalfDollars.java

 1: class HalfDollars {
 2:     public static void main(String[] arguments) {
 3:         int[] denver = { 2500000, 2900000, 3500000  };
 4:         int[] philadelphia = new int[denver.length];
 5:         int[] total = new int[denver.length];
 6:         int average;
 7:
 8:          philadelphia[0] = 2500000;
 9:          philadelphia[1] = 2900000;
10:          philadelphia[2] = 3800000;
11:
12:          total[0] = denver[0] + philadelphia[0];
13:          total[1] = denver[1] + philadelphia[1];
14:          total[2] = denver[2] + philadelphia[2];
15:          average = (total[0] + total[1] + total[2]) / 3;
16:
17:          System.out.print("2003 production: ");
18:          System.out.format("%,d%n", total[0]);
19:          System.out.print("2004 production: ");
20:          System.out.format("%,d%n", total[1]);
21:          System.out.print("2005 production: ");
22:          System.out.format("%,d%n", total[2]);
23:          System.out.print("Average production: ");
24:          System.out.format("%,d%n", average);
25:     }
26: }

The HalfDollars application uses three integer arrays to store production totals for U.S. half-dollar coins produced at the Denver and Philadelphia mints. The output of the program is as follows:

2003 production: 5,000,000
2004 production: 5,800,000
2005 production: 7,300,000
Average production: 6,033,333

The class created here, HalfDollars, has three instance variables that hold arrays of integers.

The first, which is named denver, is declared and initialized on line 3 to contain three integers: 2500000 in element 0, 2900000 in element 1, and 3500000 in element 2. These figures are the total half-dollar production at the Denver mint for three years.

The second and third instance variables, philadelphia and total, are declared in lines 4–5. The philadelphia array contains the production totals for the Philadelphia mint, and total is used to store the overall production totals.

No initial values are assigned to the slots of the philadelphia and total arrays in lines 4–5. For this reason, each element is given the default value for integers: 0.

The denver.length variable is used to give both of these arrays the same number of slots as the denver array; every array contains a length variable that you can use to keep track of the number of elements it contains.

The rest of the main() method of this application performs the following:

  • Line 6 creates an integer variable called average.

  • Lines 8–10 assign new values to the three elements of the philadelphia array.

  • Lines 12–14 assign new values to the elements of the total array. In line 12, total element 0 is given the sum of denver element 0 and philadelphia element 0. Similar expressions are used in lines 13 and 14.

  • Line 15 sets the value of the average variable to the average of the three total elements. Because average and the three total elements are integers, the average is expressed as an integer rather than a floating-point number.

  • Lines 17–24 display the values stored in the total array and the average variable, using the System.out.format() method to display the numeric values in a more readable form using commas.

This application handles arrays in an inefficient way. The statements are almost identical, except for the subscripts that indicate the array element to which you are referring. If the HalfDollars application was being used to track 100 years of production totals instead of 3 years, this approach would require a lot of redundant statements.

When dealing with arrays, you can use loops to cycle through an array’s elements instead of dealing with each element individually. This makes the code a lot shorter and easier to read. When you learn about loops later today, you see a rewrite of the current example.

Multidimensional Arrays

If you have used arrays in other languages, you might be expecting Java to support multidimensional arrays, which are arrays that contain more than one subscript and can store information in multiple dimensions.

A common use of a multidimensional array is to represent the data in an x,y grid of array elements.

Java does not support multidimensional arrays, but you can achieve the same functionality by declaring an array of arrays. Those arrays can also contain arrays, and so on, for as many dimensions as needed.

For example, consider a program that needs to accomplish the following tasks:

  • Record an integer value each day for a year

  • Organize those values by week

One way to organize this data is to create a 52-element array in which each element contains a 7-element array:

int[][] dayValue = new int[52][7];

This array of arrays contains a total of 364 integers, enough for 52 seven-day weeks. You could set the value for the first day of the 10th week with the following statement:

dayValue[9][0] = 14200;

You can use the length instance variable with these arrays as you would any other. The following statement contains a three-dimensional array of integers and displays the number of elements in each dimension:

int[][][] century = new int[100][52][7];
System.out.println("Elements in the first dimension: " + century.length);
System.out.println("Elements in the second dimension: " + century[0].length);
System.out.println("Elements in the third dimension: " + century[0][0].length);

Block Statements

Statements in Java are grouped into blocks. The beginning and ending boundaries of a block are noted with brace characters—an opening brace ({) for the beginning and a closing brace (}) for the ending.

At this point, you have used blocks to hold the variables and methods in a class definition and define statements that belong in a method.

Blocks also are called block statements because an entire block can be used anywhere a single statement could be used (they’re called compound statements in C and other languages). Each statement inside the block is then executed from top to bottom.

You can put blocks inside other blocks, just as you do when you put a method inside a class definition.

An important thing to note about using a block is that it creates a scope for the local variables created inside the block.

Scope is the part of a program in which a variable exists and can be used. If you try to use a variable outside its scope, an error occurs.

In Java, the scope of a variable is the block in which it was created. When you can declare and use local variables inside a block, those variables cease to exist after the block is finished executing. For example, the following testBlock() method contains a block:

void testBlock() {
    int x = 10;
    { // start of block
        int y = 40;
        y = y + x;
    } // end of block
}

Two variables are defined in this method: x and y. The scope of the y variable is the block it’s in, which is noted with the start of block and end of block comments.

The variable can be used only within that block. An error would result if you tried to use the y variable in another part of the testBlock() method.

The x variable was created inside the method but outside the inner block, so it can be used anywhere in the method. You can modify the value of x anywhere within the method.

Block statements usually are not used alone within a method definition, as they are in the preceding example. You use them throughout class and method definitions, as well as in the logic and looping structures you learn about next.

if Conditionals

A key aspect of any programming language is how it enables a program to make decisions. This is handled through a special type of statement called a conditional.

A conditional is a programming statement executed only if a specific condition is met.

The most basic conditional in Java is the if keyword. The if conditional uses a Boolean expression to decide whether a statement should be executed. If the expression produces a true value, the statement is executed.

Here’s a simple example that displays the message "Not enough arguments" on only one condition: If the value of the arguments.length instance variable is less than 3

if (arguments.length < 3)
   System.out.println("Not enough arguments");

If you want something else to happen when an if expression produces a false value, an optional else keyword can be used. The following example uses both if and else:

String server;
if (arguments.length < 1)
    server = "localhost";
else
    server = arguments[0];

The if conditional executes different statements based on the result of a single Boolean test.

Note

A difference between if conditionals in Java and those in other languages is that Java conditionals only produce Boolean values (true or false). In C and C++, the test can return an integer.

Using if, you can include only a single statement as the code to execute if the test expression is true and another statement if the expression is false.

However, as you learned earlier today, a block can appear anywhere in Java that a single statement can appear. If you want to do more than one thing as a result of an if statement, you can enclose those statements inside a block. Note the following snippet of code, which was used on Day 1, “Getting Started with Java”:

if (temperature > 660) {
    status = "returning home";
    speed = 5;
}

The if statement in this example contains the test expression temperature > 660. If the temperature variable contains a value higher than 660, the block statement is executed, and two things occur:

  • The status variable is given the value returning home.

  • The speed variable is set to 5.

If the temperature variable is equal to or less than 660, the entire block is skipped, so nothing happens.

All if and else statements use Boolean tests to determine whether statements are executed. You can use a boolean variable itself for this test, as in the following:

if (outOfGas)
    status = "inactive";

The preceding example uses a boolean variable called outOfGas. It functions exactly like the following:

if (outOfGas == true)
    status = "inactive";

switch Conditionals

A common programming practice is to test a variable against a value, and if it doesn’t match, test it again against a different value, and so on.

This approach can become unwieldy if you’re using only if statements, depending on how many different values you have to test. For example, you might end up with a set of if statements something like the following:

if (operation == '+')
   add(object1, object2);
else if (operation == '-')
    subtract(object1, object2);
else if (operation == '*')
    multiply(object1, object2);
else if (operation == '/')
    divide(object1, object2);

This use of if statements is called a nested if statement because each else statement contains another if until all possible tests have been made.

In some languages, a shorthand mechanism that you can use for nested if statements is to group tests and actions together in a single statement. In Java, you can group actions together with the switch statement. The following example demonstrates switch usage:

switch (grade) {
    case 'A':
        System.out.println('Great job!");
        break;
    case 'B':
        System.out.println('Good job!");
        break;
    case 'C':
        System.out.println('You can do better!");
        break;
    default:
        System.out.println('Consider cheating!");
}

A switch statement is built on a test variable; in the preceding example, the variable is the value of the grade variable, which holds a char value.

The test variable, which can be the primitive types byte, char, short, or int, is compared in turn with each of the case values. If a match is found, the statement or statements after the test are executed.

If no match is found, the default statement or statements are executed. Providing a default statement is optional—if it is omitted and there is no match for any of the case statements, the switch statement might complete without executing anything.

The Java implementation of switch is limited—tests and values can be only simple primitive types that can be cast to an int. You cannot use larger primitive types such as long or float, strings, or other objects within a switch, nor can you test for any relationship other than equality. These restrictions limit switch to the simplest cases. In contrast, nested if statements can work for any kind of test on any possible type.

The following is a revision of the nested if example shown previously. It has been rewritten as a switch statement:

switch (operation) {
    case '+':
        add(object1, object2);
        break;
    case '-':
        subtract(object1, object2);
        break;
    case '*':
        multiply(object1, object2);
        break;
    case '/':
        divide(object1, object2);
        break;
}

After each case, you can include a single result statement or as many as you need. Unlike with if statements, multiple statements don’t require a block statement.

The break statement included with each case section determines when to stop executing statements in response to a matching case. Without a break statement in a case section, after a match is made, the statements for that match and all the statements further down the switch are executed until a break or the end of the switch is found.

In some situations, this might be exactly what you want to do. Otherwise, you should include break statements to ensure that only the right code is executed. The break statement, which you use again later in the section “Breaking Out of Loops,” stops execution at the current point and jumps to the statement after the closing brace that ends the switch statement.

One handy use of falling through without a break occurs when multiple values need to execute the same statements. To accomplish this task, you can use multiple case lines with no result; the switch executes the first statement that it finds.

For example, in the following switch statement, the string x is an even number is printed if x has the values of 2, 4, 6, or 8. All other values of x cause the string x is an odd number to be printed.

switch (x) {
    case 2:
    case 4:
    case 6:
    case 8:
       System.out.println("x is an even number");
       break;
    default: System.out.println("x is an odd number");
}

In Listing 4.2, the DayCounter application takes two arguments, a month and a year, and displays the number of days in that month. A switch statement, if statements, and else statements are used.

Example 4.2. The Full Text of DayCounter.java

 1: class DayCounter {
 2:     public static void main(String[] arguments) {
 3:         int yearIn = 2008;
 4:         int monthIn = 1;
 5:         if (arguments.length > 0)
 6:             monthIn = Integer.parseInt(arguments[0]);
 7:         if (arguments.length > 1)
 8:             yearIn = Integer.parseInt(arguments[1]);
 9:         System.out.println(monthIn + "/" + yearIn + " has "
10:             + countDays(monthIn, yearIn) + " days.");
11:      }
12:
13:     static int countDays(int month, int year) {
14:         int count = -1;
15:         switch (month) {
16:             case 1:
17:             case 3:
18:             case 5:
19:             case 7:
20:             case 8:
21:             case 10:
22:             case 12:
23:                 count = 31;
24:                 break;
25:             case 4:
26:             case 6:
27:             case 9:
28:             case 11:
29:                 count = 30;
30:                 break;
31:             case 2:
32:                 if (year % 4 == 0)
33:                     count = 29;
34:                 else
35:                     count = 28;
36:                 if ((year % 100 == 0) & (year % 400 != 0))
37:                     count = 28;
38:        }
39:        return count;
40:     }
41: }

This application uses command-line arguments to specify the month and year to check. The first argument is the month, which should be expressed as a number from 1 to 12. The second argument is the year, which should be expressed as a full four-digit year.

After compiling the program, type the following at a command line to see the number of days in April 2008:

java DayCounter 4 2008

The output is the following:

4/2008 has 30 days.

If you run it without arguments, the default month of January 2008 is used, and the output is the following:

1/2008 has 31 days.

The DayCounter application uses a switch statement to count the days in a month. This statement is part of the countDays() method in lines 13–40 of Listing 4.2.

The countDays() method has two int arguments: month and year. The number of days is stored in the count variable, which is given an initial value of -1 that is replaced by the correct count later.

The switch statement that begins on line 15 uses month as its conditional value.

The number of days in a month is easy to determine for 11 months of the year. January, March, May, July, August, October, and December have 31 days. April, June, September, and November have 30 days.

The count for these 11 months is handled in lines 16–30 of Listing 4.2. Months are numbered from 1 (January) to 12 (December), as you would expect. When one of the case statements has the same value as month, every statement after that is executed until break or the end of the switch statement is reached.

February is a little more complex and is handled in lines 31–37 of the program. Every leap year has 29 days in February, whereas other years have 28. A leap year must meet either of the following conditions:

  • The year must be evenly divisible by 4 and not evenly divisible by 100.

  • The year must be evenly divisible by 400.

As you learned on Day 2, “The ABCs of Programming,” the modulus operator % returns the remainder of a division operation. This is used with several if-else statements to determine how many days there are in February, depending on what year it is.

The if-else statement in lines 32–35 sets count to 29 when the year is evenly divisible by 4 and sets it to 28 otherwise.

The if statement in lines 36–37 uses the & operator to combine two conditional expressions: year % 100 == 0 and year % 400 != 0. If both these conditions are true, count is set to 28.

The countDays method ends by returning the value of count in line 39.

When you run the DayCounter application, the main() method in lines 2–11 is executed.

In all Java applications, command-line arguments are stored in an array of String objects. This array is called arguments in DayCounter. The first command-line argument is stored in argument[0], the second in argument[1], and upward until all arguments have been stored. If the application is run with no arguments, the array is created with no elements.

Lines 3–4 create yearIn and monthIn, two integer variables to store the year and month that should be checked.

The if statement in line 5 uses arguments.length to make sure that the arguments array has at least one element. If it does, line 6 is executed.

Line 6 calls parseInt(), a class method of the Integer class, with argument[0] as an argument. This method takes a String object as an argument, and if the string could be a valid integer, it returns that value as an int. This converted value is stored in monthIn. A similar thing happens in line 7; parseInt() is called with argument[1], and this is used to set yearIn.

The output of the program is displayed in lines 9–11. As part of the output, the countDays() method is called with monthIn and yearIn, and the value returned by this method is displayed.

Note

At this point, you might want to know how to collect input from a user in a program rather than using command-line arguments to receive it. There isn’t a method comparable to System.out. println() that receives input. Instead, you must learn a bit more about Java’s input and output classes before you can receive input in a program without a graphical user interface. This topic is covered during Day 15, “Working with Input and Output.”

for Loops

A for loop is used to repeat a statement until a condition is met. Although for loops frequently are used for simple iteration in which a statement is repeated a certain number of times, for loops can be used for just about any kind of loop.

The for loop in Java looks roughly like the following:

for (initialization; test;increment) {
    statement;
}

The start of the for loop has three parts:

  • initialization is an expression that initializes the start of the loop. If you have a loop index, this expression might declare and initialize it, such as int i = 0. Variables that you declare in this part of the for loop are local to the loop itself; they cease to exist after the loop is finished executing. You can initialize more than one variable in this section by separating each expression with a comma. The statement int i = 0, int j = 10 in this section would declare the variables i and j, and both would be local to the loop.

  • test is the test that occurs before each pass of the loop. The test must be a Boolean expression or a function that returns a boolean value, such as i < 10. If the test is true, the loop executes. When the test is false, the loop stops executing.

  • increment is any expression or function call. Commonly, the increment is used to change the value of the loop index to bring the state of the loop closer to returning false and stopping the loop. The increment takes place after each pass of the loop. Similar to the initialization section, you can put more than one expression in this section by separating each expression with a comma.

The statement part of the for loop is the statement that is executed each time the loop iterates. As with if, you can include either a single statement or a block statement. The previous example used a block because that is more common. The following example is a for loop that sets all slots of a String array to the value Mr.:

String[] salutation = new String[10];
int i; // the loop index variable

for (i = 0; i < salutation.length; i++)
    salutation[i] = "Mr.";

In this example, the variable i serves as a loop index; it counts the number of times the loop has been executed. Before each trip through the loop, the index value is compared with salutation.length, the number of elements in the salutation array. When the index is equal to or greater than salutation.length, the loop is exited.

The final element of the for statement is i++. This causes the loop index to increment by 1 each time the loop is executed. Without this statement, the loop would never stop.

The statement inside the loop sets an element of the salutation array equal to "Mr.". The loop index is used to determine which element is modified.

Any part of the for loop can be an empty statement; in other words, you can include a semicolon with no expression or statement, and that part of the for loop is ignored. Note that if you do use an empty statement in your for loop, you might have to initialize or increment any loop variables or loop indexes yourself elsewhere in the program.

You also can have an empty statement as the body of your for loop if everything you want to do is in the first line of that loop. For example, the following for loop finds the first prime number higher than 4,000. (It employs a method called notPrime(), which returns a Boolean value, presumably to indicate when i is not prime.)

for (i = 4001; notPrime(i); i += 2)
;

A common mistake in for loops is to accidentally put a semicolon at the end of the line that includes the for statement:

for (i = 0; i < 10; i++);
    x = x * i; // this line is not inside the loop!

In this example, the first semicolon ends the loop without executing x = x * i as part of the loop. The x = x * i line is executed only once because it is outside the for loop entirely. Be careful not to make this mistake in your Java programs.

The next project you undertake is a rewrite of the HalfDollar application that uses for loops to remove redundant code.

The original application works only with an array that is three elements long. The new version, shown in Listing 4.3, is shorter and more flexible (but it returns the same output).

Example 4.3. The Full Text of HalfLooper.java

 1: class HalfLooper {
 2:     public static void main(String[] arguments) {
 3:         int[] denver = { 2500000, 2900000, 3500000 };
 4:         int[] philadelphia = { 2500000, 2900000, 3800000 };
 5:         int[] total = new int[denver.length];
 6:         int sum = 0;
 7:
 8:         for (int i = 0; i < denver.length; i++) {
 9:             total[i] = denver[i] + philadelphia[i];
10:             System.out.format((i + 2003) + " production: %,d%n",
11:                 total[i]);
12:             sum += total[i];
13:         }
14:
15:         System.out.format("Average production: %,d%n",
16:             (sum / denver.length));
17:     }
18: }

The output of the program is as follows:

2003 production: 5,000,000
2004 production: 5,800,000
2005 production: 7,300,000
Average production: 6,033,333

Instead of going through the elements of the three arrays one by one, this example uses a for loop. The following things take place in the loop, which is contained in lines 8–13 of Listing 4.3:

  • Line 8—The loop is created with an int variable called i as the index. The index increments by 1 for each pass through the loop and stops when i is equal to or greater than denver.length, the total number of elements in the denver array.

  • Lines 9–11—The value of one of the total elements is set using the loop index and then displayed with some text identifying the year.

  • Line 12—The value of a total element is added to the sum variable, which is used to calculate the average yearly production.

Using a more general-purpose loop to iterate over an array enables you to use the program with arrays of different sizes and still have it assign correct values to the elements of the total array and display those values.

Note

Java also includes a for loop that can be used to iterate through all the elements of data structures such as vectors, linked lists, hash sets, and other collections. It’s covered along with those structures on Day 8, “Data Structures.”

while and do Loops

The remaining types of loops are while and do. As with for loops, while and do loops enable a block of Java code to be executed repeatedly until a specific condition is met. Whether you use a for, while, or do loop is mostly a matter of your programming style.

while Loops

The while loop repeats a statement for as long as a particular condition remains true. Here’s an example:

while (i < 13) {
    x = x * i++; // the body of the loop
}

The condition that accompanies the while keyword is a Boolean expression—i < 13 in the preceding example. If the expression returns true, the while loop executes the body of the loop and then tests the condition again. This process repeats until the condition is false.

Although the preceding loop uses opening and closing braces to form a block statement, the braces are not needed because the loop contains only one statement: x = x * i++. Using the braces does not create any problems, though, and the braces will be required if you add another statement inside the loop later.

The ArrayCopier application in Listing 4.4 uses a while loop to copy the elements of an array of integers (in array1) to an array of float variables (in array2), casting each element to a float as it goes. The one catch is that if any of the elements in the first array is 1, the loop immediately exits at that point.

Example 4.4. The Full Text of ArrayCopier.java

 1: class ArrayCopier {
 2:     public static void main(String[] arguments) {
 3:         int[] array1 = { 7, 4, 8, 1, 4, 1, 4 };
 4:         float[] array2 = new float[array1.length];
 5:
 6:         System.out.print("array1: [ ");
 7:         for (int i = 0; i < array1.length; i++) {
 8:            System.out.print(array1[i] + " ");
 9:         }
10:         System.out.println("]");
11:
12:         System.out.print("array2: [ ");
13:         int count = 0;
14:         while ( count < array1.length && array1[count] != 1) {
15:             array2[count] = (float) array1[count];
16:             System.out.print(array2[count++] + " ");
17:         }
18:         System.out.println("]");
19:     }
20: }

The output of the program is as follows:

array1: [ 7 4 8 1 4 1 4 ]
array2: [ 7.0 4.0 8.0 ]

Here is what’s going on in the main() method:

  • Lines 3–4 declare the arrays; array1 is an array of integers, which are initialized to some suitable numbers. array2 is an array of floating-point numbers that is the same length as array1 but doesn’t have any initial values.

  • Lines 6–10 are for output purposes; they simply iterate through array1 using a for loop to print out its values.

  • Lines 13–17 are where the interesting stuff happens. This bunch of statements both assigns the values of array2 (converting the numbers to floating-point numbers along the array) and prints it out at the same time. You start with a count variable, which keeps track of the array index elements. The test in the while loop keeps track of the two conditions for exiting the loop, where those two conditions are running out of elements in array1 or encountering a 1 in array1. (Remember, that was part of the original description of what this program does.)

    You can use the logical conditional && to keep track of the test; remember that && makes sure that both conditions are true before the entire expression is true. If either one is false, the expression returns false and the loop exits.

The program’s output shows that the first four elements in array1 were copied to array2, but there was a 1 in the middle that stopped the loop from going any further. Without the 1, array2 should end up with all the same elements as array1.

If the while loop’s test initially is false the first time it is tested (for example, if the first element in that first array is 1), the body of the while loop will never be executed. If you need to execute the loop at least once, you can do one of two things:

  • Duplicate the body of the loop outside the while loop.

  • Use a do loop (which is described in the following section).

The do loop is considered the better solution of the two.

do-while Loops

The do loop is just like a while loop with one major difference—the place in the loop when the condition is tested.

A while loop tests the condition before looping, so if the condition is false the first time it is tested, the body of the loop never executes.

A do loop executes the body of the loop at least once before testing the condition, so if the condition is false the first time it is tested, the body of the loop already will have executed once.

The following example uses a do loop to keep doubling the value of a long integer until it is larger than 3 trillion:

long i = 1;
do {
    i *= 2;
    System.out.print(i + " ");
} while (i < 3000000000000L);

The body of the loop is executed once before the test condition, i < 3000000000000L, is evaluated; then, if the test evaluates as true, the loop runs again. If it is false, the loop exits. Keep in mind that the body of the loop executes at least once with do loops.

Breaking Out of Loops

In all the loops, the loop ends when a tested condition is met. There might be times when something occurs during execution of a loop and you want to exit the loop early. In that case, you can use the break and continue keywords.

You already have seen break as part of the switch statement; break stops execution of the switch statement, and the program continues. The break keyword, when used with a loop, does the same thing—it immediately halts execution of the current loop. If you have nested loops within loops, execution picks up with the next outer loop. Otherwise, the program simply continues executing the next statement after the loop.

For example, recall the while loop that copied elements from an integer array into an array of floating-point numbers until either the end of the array or a 1 was reached. You can test for the latter case inside the body of the while loop and then use break to exit the loop:

int count = 0;
while (count < array1.length) {
    if (array1[count] == 1)
        break;
    array2[count] = (float) array1[count++];
}

The continue keyword starts the loop over at the next iteration. For do and while loops, this means that the execution of the block statement starts over again; with for loops, the increment expression is evaluated, and then the block statement is executed.

The continue keyword is useful when you want to make a special case out of elements within a loop. With the previous example of copying one array to another, you could test for whether the current element is equal to 1 and use continue to restart the loop after every 1 so that the resulting array never contains zero. Note that because you’re skipping elements in the first array, you now have to keep track of two different array counters:

int count = 0;
int count2 = 0;
while (count++ <= array1.length) {
    if (array1[count] == 1)
       continue;
    array2[count2++] = (float)array1[count];
}

Labeled Loops

Both break and continue can have an optional label that tells Java where to resume execution of the program. Without a label, break jumps outside the nearest loop to an enclosing loop or to the next statement outside the loop. The continue keyword restarts the loop it is enclosed within. Using break and continue with a label enables you to use break to go to a point outside a nested loop or to use continue to go to a loop outside the current loop.

To use a labeled loop, add the label before the initial part of the loop, with a colon between the label and the loop. Then, when you use break or continue, add the name of the label after the keyword itself, as in the following:

out:
    for (int i = 0; i <10; i++) {
        while (x < 50) {
            if (i * x++ > 400)
                break out;
            // inner loop here
        }
        // outer loop here
    }

In this snippet of code, the label out labels the outer loop. Then, inside both the for and while loops, when a particular condition is met, a break causes the execution to break out of both loops. Without the label out, the break statement would exit the inner loop and resume execution with the outer loop.

The Conditional Operator

An alternative to using the if and else keywords in a conditional statement is to use the conditional operator, sometimes called the ternary operator. The conditional operator is called a ternary operator because it has three operands.

The conditional operator is an expression, meaning that it returns a value—unlike the more general if, which can result in only a statement or block being executed. The conditional operator is most useful for short or simple conditionals and looks like the following line:

test ? trueresult : falseresult;

The test is an expression that returns true or false, just like the test in the if statement. If the test is true, the conditional operator returns the value of trueresult. If the test is false, the conditional operator returns the value of falseresult. For example, the following conditional tests the values of myScore and yourScore, returns the larger of the two as a value, and assigns that value to the variable ourBestScore:

int ourBestScore = myScore > yourScore ? myScore : yourScore;

This use of the conditional operator is equivalent to the following if-else code:

int ourBestScore;
if (myScore > yourScore)
   ourBestScore = myScore;
else
   ourBestScore = yourScore;

The conditional operator has a low precedence—usually it is evaluated only after all its subexpressions are evaluated. The only operators lower in precedence are the assignment operators. For a refresher on operator precedence, refer to Table 2.6 in Day 2, “The ABCs of Programming.”

Caution

The ternary operator is of primary benefit to experienced programmers creating complex expressions. Its functionality is duplicated in simpler use of if-else statements, so there’s no need to use this operator while you’re beginning to learn the language. The main reason it’s introduced in this book is because you’ll encounter it in the source code of other Java programmers.

Summary

Now that you have been introduced to lists, loops, and logic, you can make a computer decide whether to repeatedly display the contents of an array.

You learned how to declare an array variable, assign an object to it, and access and change elements of the array. With the if and switch conditional statements, you can branch to different parts of a program based on a Boolean test. You learned about the for, while, and do loops, and you learned that each enables a portion of a program to be repeated until a given condition is met.

It bears repeating: You’ll use all three of these features frequently in your Java programs.

You’ll use all three of these features frequently in your Java programs.

Q&A

Q

I declared a variable inside a block statement for an if. When the if was done, the definition of that variable vanished. Where did it go?

A

In technical terms, block statements form a new lexical scope. This means that if you declare a variable inside a block, it’s visible and usable only inside that block. When the block finishes executing, all the variables you declared go away.

It’s a good idea to declare most of your variables in the outermost block in which they’ll be needed—usually at the top of a block statement. The exception might be simple variables, such as index counters in for loops, where declaring them in the first line of the for loop is an easy shortcut.

Q

Why can’t I use switch with strings?

A

Strings are objects in Java, and switch works only for the primitive types byte, char, short, and int. To compare strings, you have to use nested if statements, which enable more general expression tests, including string comparison.

Quiz

Review today’s material by taking this three-question quiz.

Questions

1.

Which loop is used to execute the statements in the loop at least once before the conditional expression is evaluated?

  1. do-while

  2. for

  3. while

2.

Which operator returns the remainder of a division operation?

  1. /

  2. %

  3. ?

3.

Which instance variable of an array is used to find out how big it is?

  1. size

  2. length

  3. MAX_VALUE

Answers

1.

a. In a do-while loop, the while conditional statement appears at the end of the loop. Even if it is initially false, the statements in the loop are executed once.

2.

b. The modulus operator (“%”).

3.

b.

Certification Practice

The following question is the kind of thing you could expect to be asked on a Java programming certification test. Answer it without looking at today’s material or using the Java compiler to test the code.

Given:

public class Cases {
    public static void main(String[] arguments) {
        float x = 9;
        float y = 5;
        int z = (int)(x / y);
        switch (z) {
            case 1:
                x = x + 2;
            case 2:
                x = x + 3;
            default:
                x = x + 1;
        }
        System.out.println("Value of x: " + x);
    }
}

What will be the value of x when it is displayed?

  1. 9.0

  2. 11.0

  3. 15.0

  4. The program will not compile.

The answer is available on the book’s website at http://www.java21days.com. Visit the Day 4 page and click the Certification Practice link.

Exercises

To extend your knowledge of the subjects covered today, try the following exercises:

  1. Using the countDays() method from the DayCounter application, create an application that displays every date in a given year in a single list from January 1 to December 31.

  2. Create a class that takes words for the first 10 numbers (“one” up to “ten”) and converts them into a single long integer. Use a switch statement for the conversion and command-line arguments for the words.

Where applicable, exercise solutions are offered on the book’s website at http://www.java21days.com.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset