In this chapter, you will learn how to add control to the programs you write. Java supports several control constructs, or statement groups, that control the way your program behaves. You can control when certain code executes and you can request that Java repeat several statements as many times as you require.
This chapter's control topics form the basis for any and all programs that you write. Only when you are well-grounded in program control can you write effective programs. This chapter attempts to show you examples of controlling statements and explains when and where you should use such statements.
Now that you've seen how to define Java data, you need to know how to manipulate that data through program control. The Java language consists of data and statements that work on that data. Often, programmers group statements together in blocks of code. A block of code is one or more statements enclosed within a pair of braces. The following is a block of code:
{
count++;
System.out.println("The count is now higher");
}
To help show where a block begins and ends, programmers often indent the body of blocks as done here. Therefore, in a program with lots of blocks and embedded blocks of code (one block can contain several other blocks of code), the indention helps you spot where blocks begin and end.
As you progress through this and the next chapter, you'll see why the block concept is so critical for good programming practices.
In addition to blocks, you'll use labels in some of your programs. When you want to mark a program location for subsequent reference, you can type a label to the left of that location. A label is a named identifier, so when you make up a name for a label, use the same naming-rules as you use for variables (see chapter 10, "Java Language Fundamentals").
A label always appears to the left of a statement or on a line by itself and ends with a colon, :. The following group of statements contains two blocks and two labels:
here: result = (a < b) ? a : b;
{
g.drawString("You have not reached the threshold yet.", 100, 200);
{
int ans = 0;
again: // A label can appear by itself
g.drawString("Do you want to continue? (Y/N)", 300, 200);
getAnswer(ans);
if ((ans == 'Y') || (ans == 'y'))
break nextAns;
}
}
The first label is named here (the colon is never considered part of the name) and the second label is again. here appears to the left of a statement and that statement marks here's location. again appears by itself on a line. Often, programmers put labels on lines by themselves to make locating the labels easier.
In addition to the blocks and labels that comprise programs, most programs consist of statement combinations that perform the following actions:
The following sections describe how you can accomplish these broad patterns of program controlling statements. In a nutshell, the controlling statements you'll learn here are action commands that control program flow. Much of your programming will require that you modify the flow of your program statements so that certain statements execute repeatedly and that other statements execute only under specific conditions.
Much of a program executes sequentially. The sample program from chapter 9, "Overview of Java Code," that you entered contained listing 11.1's paint() procedure. The procedure executes sequentially, that is, one statement after another from top to bottom. When the applet control reaches the paint() procedure, control begins at the first comment and continues through the getColor() and drawString() procedure calls.
Listing 11.1 The paint() Procedure's Body Executes Sequentially
public void paint(Graphics g)
{
// Change subsequent text color to red
g.setColor(Color.red);
// Write a simple message in the window
g.drawString("Very simple!", 75, 100);
}
Figure 11.1 illustrates how sequential flow works. Rarely is a program completely sequential. The majority of program statements, however, do execute sequentially one statement after another. Therefore, unless you change the program flow as you'll learn to do throughout the rest of this chapter, the statements execute sequentially.
Sequential flow occurs top-to-bottom, with one statement executing before the next.
Although a program will not do anything you don't tell it to do, you can give your programs flexibility to execute certain statements based on data contents. Suppose you write an applet for your company's sales staff Web page. Salespeople can display the Web page and, through the Web page, run your applet that calculates and displays their commission bonus when they enter their current sales levels for the month.
Many salespeople's salaries are based on a standard pay scale with added bonus commissions paid after a certain level of sales is met. Some of the salespeople will get the bonus and others will not. Your applet should determine when the bonus should be computed. If a salesperson has not reached the required level of sales, your applet should skip the bonus calculation routine but if the salesperson has surpassed the minimum threshold, your applet should calculate the bonus.
If sequential execution was the only way a program would run, you could not calculate the bonus one time and then leave out the calculation the next. With decision-making logic, however, you can direct your program to calculate and do work only when certain conditions are met.
Figure 11.2 shows an overview of decision-making logic. The statements in your program execute one after another until decision-making logic changes the sequential order. When your program encounters a statement that controls the decision-making, the statement can test a certain condition to see if that condition is true or false. If the condition is true, the true-based statements execute and if the condition is false, the false-based statements execute.
Decision-making flow executes one or more statements only when a certain condition is true or false.
Decision-making logic can be either one-legged or two-legged. A one-legged decision occurs when a true condition executes part of the program and skips that part otherwise. A two-legged decision occurs when a true condition executes part of the program and a false condition executes the other part.
You use such decision-making logic all the time. Consider the following statements:
The Java language contains the following keywords that produce the decision-making logic:
Actually, you already know about another kind of decision-making Java tool: the conditional operator. As you'll soon see, the conditional operator uses identical logic to the if-else statement.
Here is the format of Java's if statement:
if (condition)
{ block of one or more Java statements; }
Learn the Format
The if statement's condition is an expression that evaluates to true or false. Therefore, the condition always contains a comparison operator (and possibly a logical operator) or a boolean variable or literal. Therefore, condition might be an expression such as total <= 4000.00 or ((hits == 0) && (answer != 'N')) or toContinue (defined as a boolean variable).
If and only if the condition is true, Java executes the statement or statements enclosed in the block of code. If, however, the condition evaluates to false, Java completely skips the block and continues execution with the statement that follows the block's closing brace. The if decides, therefore, whether or not the code block executes.
Consider the following if statement:
if (age >= 21)
{ g.drawString("You have authorization for the payment", 25, 50);
makePmt(pmt);
}
// Rest of program continues
The two statements in the if block will execute only if age contains a value of 21 or more. If age is less than 21, the block of code does not execute. Whether or not the block executes does not keep the subsequent statements in the program from continuing.
The condition does not have to compare just numeric data. You can compare any kind of data values inside the condition.
A good use for if is input verification. When you ask the user for a value, you should check the value to make sure the user entered a reasonable answer. For example, the following code asks the user for his or her age. If the user enters zero or a negative value, the program's if statement displays an error message and prompts the user again:
getAge(age); // Calls a procedure to get the user's age
if (age <= 0)
{
// The following lines output to the user's screen
System.out.println('\007'); // The ASCII beep character
System.out.println("You entered a bad age value.");
System.out.println("Try again please.");
getAge(age);
}
// Code goes here to process the age
The if-else is actually an extension of the if statement. Here is the format of the if-else statement:
if (condition)
{ block of one or more Java statements; }
else
{ block of one or more Java statements; }
If the condition evaluates to true, the first block of Java statements executes. If, however, the condition evaluates to false, the second block of Java statements executes.
In the previous chapter, you saw how to use the conditional operator to find the minimum of two values. Here is the conditional statement as you saw it:
minVal = (a < b) ? a : b;
You rewrite the conditional using an if-else statement. Here is the equivalent if-else that stores the minimum value in minVal:
if (a < b)
{ minVal = a; } // Store a if a is the smallest of the two values
else
{ minVal = b; } // Store b if b is the smallest of the two values
Which is easier to type? Which is easier to understand? You type a program once but you maintain and change a program many times. Save time by writing clear Java programs. Although the conditional requires less typing when you first enter the code, most would agree that the if-else is easier to understand. If you were to make a change to this program, you would not have to spend as much time figuring out what the if-else does as you might for the conditional. Of course, ample comments would explain the conditional's goal but you should both comment and write clear code. Less is not always better when it comes to clear Java programs.
The section of code in listing 11.2 computes a payroll amount based on the following general rules:
Listing 11.2 The paint() Procedure's Body Executes Sequentially
// Assume all variables are initialized to zero before the code begins
// Check for double-time
if (hours > 50)
{ dbleTime = 2.0 * payRate * (float) (hours - 50);
halfTime = 1.5 * payRate * 10.0; // 1.5 pay for middle 10 hours
else
{ dbleTime = 0.0; } // No double because no hours over 50
// Check for time-and-a-half
if ((hours > 40) && (hours <= 50))
{ halfTime = 1.5 * payRate * (float)(hours - 40); }
// Compute regular pay for everybody
if (hours >= 40)
{ regPay = (float)hours * payRate; }
// Add the parts to get the total gross pay
totalPay = regPay + halfTime + dbleTime;
The code assumes that you've already defined all the variables before using them.
The switch acts like a multiple-choice statement in that switch lets your code select from one of several alternatives. The switch statement does little more than a complex if-else statement can do but the switch is much cleaner and easier to follow. For many cases, the switch statement makes choosing from one of several alternatives simple.
The body of an if or else can contain additional if-else statements. Support you need to print a message based on a user's department code. The following if-else does just that:
if (deptCode == 1)
{ g.drawString("Meeting at 11:00", 50, 100); }
else
if (deptCode == 2)
{ g.drawString("Meeting at 2:00", 50, 100); }
else
if (deptCode == 3)
{ g.drawString("Meeting at 10:00", 50, 100); }
else
if (deptCode == 4)
{ g.drawString("Meeting at 8:30", 50, 100); }
else
if (deptCode == 5)
{ g.drawString("Meeting at 3:00", 50, 100); }
else
if (deptCode == 6)
{ g.drawString("Meeting at 9:00", 50, 100); }
else
{ g.drawString("**Your code is not 1 through 6!", 50, 100);
Although you can probably follow this complex embedded if-else logic, the switch makes much better use of your programming skills because switch makes multiple-choice selections simple to see. In addition, if the bodies in this complex if-else contain more than one statement, the logic becomes extremely difficult to follow. If, on the other hand, the body of a switch statement's multiple-choice actions require more than one statement, the switch does not become more convoluted.
Here is the format of the switch statement:
switch (expression)
{ case (expression) : { block of one or more Java statements; }
break;
[ { case (expression) : { block of one or more Java statements; }
break;
{ case (expression) : { block of one or more Java statements; }
break;
// The case/break pattern continues as long
// as you have multiple-choice selections
]
[ default: : { block of one or more Java statements; }
break;
]
}
Remember that the square brackets inside formats indicate optional statement parts. The switch statement contains one or more case statement bodies depending on the number of multiple-choice selections you have to make. The expression evaluates to an integer or character data type. Unlike the condition inside an if-else statement, switch can check only for equalities (perhaps the only drawback to switch).
Although the switch statement's format looks complex, switch makes a lot of sense when you see an actual switch statement. Here is the switch statement's equivalent to the previous embedded if-else logic:
switch (deptCode) // Parentheses clarify the value being checked
{
case 1 : { g.drawString("Meeting at 11:00", 50, 100);
break; }
case 2 : { g.drawString("Meeting at 2:00", 50, 100);
break; }
case 3 : { g.drawString("Meeting at 10:00", 50, 100);
break; }
case 4 : { g.drawString("Meeting at 8:30", 50, 100);
break; }
case 5 : { g.drawString("Meeting at 3:00", 50, 100);
break; }
case 6 : { g.drawString("Meeting at 9:00", 50, 100);
break; }
default { g.drawString("**Your code is not 1 through 6!", 50, 100);
break; }
}
Sometimes, I use a switch style that other Java programmers do not prefer. For example, I use braces to show clearly the bodies of each case selection but the braces that form the blocks are optional. In addition, the break after default is optional (even the whole default is optional) but I use the break there too so that if I rearrange the case statements and turn the default into a case, I'll remember to include the break where it's needed (after the case).
The switch statement first evaluates the expression following the switch keyword. Remember that the expression must evaluate to an integer or to a character. Java then looks for the case whose value matches the switch's expression. If none of the case values match the switch value, Java executes the code in the default body. If you do not include the default code, Java will not execute any of the switch statement's blocks unless one of the case values matches the switch value.
Those pesky break statements are required except in rare cases. If you do not include the break statements, Java would fall-through to subsequent case logic. In other words, if the break did not appear after the case 5 expression in this example, the user would not only see department 5's meeting message but also department 6's as well. Of course, the nature of break also adds some flexibility. For example, you could specify the same case for several values by stacking empty case statements like this:
case 4:
case 5:
case 6 : { g.drawString("Meeting at 9:00", 50, 100);
break; }
You've already seen code that contains procedure calls. A procedure call occurs when a program statement contains the name of a procedure (or method). A procedure or method is easy to spot because of the parentheses that follow the procedure or method name. The procedure or method is a built-in, or pre-written section of code. Generally, you'll call procedures by placing their name on a line such as this:
g.drawString("This is output", 50, 100); // Calls the drawString() method
Again, in Java, the distinction between methods and procedures is not really critical at this point. They both act like detours from your code. Methods generally follow a period as in this drawString() example and procedures often appear by themselves. Generally, you'll supply all your procedure code whereas Java and external suppliers often supply methods.
The drawString() method demonstrates the advantage of pre-written methods. Instead of writing all the tedious code necessary to draw a string of characters on your screen, you can call the drawString() method that Java supplies for you. Figure 11.3 shows what happens when you call a method program procedure. Your code executes the procedure and then continues its original execution path.
A method or procedure call acts like a program detour.
Java contains several class methods and procedures you can call. This book will describe many of the more popular ones when the need arises.
Methods and procedures sometimes have values inside their parentheses and sometimes they do not. The values are called parameters and the parentheses make up the parameter list. Depending on the procedure, the parameter might be a one-way pass or a return. In other words, you may send a value to a method by enclosing the value inside the parameter list and the method will calculate or perform some other function based on the value you send. You might also enclose a variable inside a parameter list that you want the procedure to fill up for you. Once the method or procedure returns control to your program, the returned parameter will hold the value you wanted computed.
When a program loops, one or more statements execute repeatedly. Of course, you must supply a way for the looping to stop, or you'll have an endless loop and your users will get tired of waiting for the applet to stop (which it won't do without the user's intervention) and you will be embarrassed by the logic error!
Figure 11.4 illustrates how looping operates. A section of code, usually but not always a block or a section of embedded blocks, keeps repeating. Looping helps you perform repeated calculations, detailed reporting, error correction, and code restarts. Computers are dumb; they don't do anything that your program does not specifically tell them to do. Computers, however, are very fast! Your program can loop several hundred or even thousands of times per second. Therefore, loops provide a way for you to perform repeated tasks quickly.
Loops occur when you repeat sections of code over and over and....
Here are the kinds of loops that Java supports:
Make sure that you distinguish between loops and decision-making statements. In a decision-making statement such as if-else, the condition determines whether or not a block of code executes once. In a looping statement, the condition determines how many times the block executes.
the while loop continues as long as a condition is true. Here is the format of the while statement:
while (condition)
{ block of one or more Java statements; }
While the condition remains true, the block executes but as soon as the condition becomes false, the loop body stops executing. It is incumbent upon you to modify the condition within the loop or the while will never stop. The condition must evaluate to a boolean true or false expression.
In some cases, the body of the while will never execute. If the condition is false upon entering the while loop, Java skips the loop body and continues with the rest of the program. Earlier, you saw how an if statement can inform a user if the user enters invalid data. With looping, you can take the user's input validation a step further: you can keep asking the user for an answer until the user enters a value that falls within your program's expected range.
The following code uses a while loop to keep asking the user for an age value until the user enters a value greater than zero:
getAge(age); // Calls a procedure to get the user's age
while (age <= 0)
{
// The following lines output to the user's screen
System.out.println('\007'); // The ASCII beep character
System.out.println("\nYou entered a bad age value.");
System.out.println("Try again please.");
getAge(age);
}
System.out.println("\nThank you.");
// When execution reaches here, you have an age greater than 0
Here is an example of the user's output screen upon coming across this code in an applet:
How old are you? -16
<beep>
You entered a bad age value.
Try again please.
How old are you? 0
You entered a bad age value.
Try again please.
How old are you? 16
Thank you.
Assume that the getAge() procedure displays the message that asks the user for the user's age. The System.out.println() method is a built-in method that prints a line of output on your screen. The extra \n at the beginning of some of the strings force a blank line before the string prints. The \n is the escape sequence for newline (see chapter 10, "Java Language Fundamentals").
The do loop is virtually identical to the while loop with this exception: Whereas the while loop tests its condition before executing the body of the loop the first time, the do loop tests its the condition after executing the body of the loop. Therefore, the do loop body always executes at least once.
Here is the do loop's format:
do
{ block of one or more Java statements; }
while (condition)
Notice that do contains the while command but the presence of do makes the do loop behave differently from the simple while loop. The choice of while or do depends on your preference and the logic involved. Generally, you'll use whichever suits your needs but remember that do always executes if body at least once you must be careful not to execute code that you want looped only under certain conditions.
Here is the input validation routine rewritten with a do loop:
getAge(age); // Calls a procedure to get the user's age
if (age <= 0) // Tell about error only if bad input occurred
{ do
{
// The following lines output to the user's screen
System.out.println('\007'); // The ASCII beep character
System.out.println("\nYou entered a bad age value.");
System.out.println("Try again please.");
getAge(age);
}
while (age <= 0)
}
System.out.println("\nThank you.");
// When execution reaches here, you have an age greater than 0
The code behaves exactly the same as the while loop's code. The do necessitates the if statement's inclusion because if the user entered a valid age, you will not want to print the error messages.
The for loop repeats a series of statements a specific number of times. Unlike while and do, for is a determinate loop. That is, when you write your program, you can usually determine how many times the loop takes place. The while and do loops execute only until a condition becomes false. You'll often code the for loop to loop until a count or countdown is reached.
The for statement encloses one or more Java statements that form the body of the loop. Here is the for statement's format:
for (startExpression; testExpression; countExpression)
{ block of one or more Java statements; }
Java evaluates the startExpression before the loop begins. Typically, the startExpression is an assignment statement (such as ctr = 1;) but the startExpression can be any legal expression you specify. Java evaluates the startExpression only once, at the top of the loop (right before the loop begins).
The for statement tests is condition at the top of the loop. Here's the way the test works:
A count is one of the quickest ways to see how the for loop works. Consider the following for loop:
for (ctr = 1; ctr <= 10; ctr++)
{ System.out.println(ctr); }
When this code runs, here is what the user sees:
1
2
3
4
5
6
7
8
9
10
The startExpression executes only once before the loop begins. Therefore, Java assigns the 1 to ctr before entering the loop's body. As long as the testExpression is true (and upon entering the loop, ctr is less than 10), the loop body continues. Once the loop body finishes, Java performs the countExpression, or in this case, Java increments the ctr variable. It takes ten iterations (loop body executions) for ctr to hold 10 and force the testExpression to false.
for loops don't have to count up; here's code that produces a countdown:
for (ctr = 10; ctr > 0; ctr--)
{ System.out.println(ctr); }
System.out.println("Blast off!");
The output appears here:
10
9
8
7
6
5
4
3
2
1
Blast off!
The for loops gives you tremendous power for stepping through an array. Suppose that you want to add a list of 100 salespeople's total sales stored in an array named sales. Without arrays, you would have to add all 100 variables together which would be too time-consuming to code and messy. With arrays you would still have to add each array element unless you use a for loop. The following code sums the 100 salespeople's sales:
float totalSales = 0.0; // Define and initialize the total variable
for (ctr=0; ctr<100; ctr++)
{ totalSales += sales[ctr]; } // Adds each salesperson's sales
When the final loop iteration executes, totalSales holds the sum of all the individual sales figures. Obviously, this code assumes that you've already defined and initialized the sales array with each of the 100 salespeople's dollar sales.
The following code prints all even and then all odd numbers below 20:
System.out.println("Even numbers below 20:");
for (num = 2; num <= 20; num+=2) // Adds 2 each iteration
{ System.out.println(num); }
System.out.println("Odd numbers below 20:");
for (num = 1; num <= 20; num+=2) // Adds 2 each iteration
{ System.out.println(num); }
Figure 11.5 shows you how the even number for loop executes. The line shows you the logic through the for loop's execution. As you can see from the figure, the startExpression occurs only once, the countExpression occurs after the body of the loop executes, and the testExpression occurs before the loop body executes.
Study the for loop's execution path.
Which Loop Is Best?
The body of a for loop can contain any statement including another for loop. A nested for loop lets you repeat a loop. Suppose that you want to print five sets of the numbers from 1 to 10. You could use a for loop to print the numbers from 1 to 10 as follows:
for (num=1; num<=10; num++)
{ System.out.print( num + ", "); }
The System.out.print() (as opposed to the System.out.println() that you've already seen) suppresses the line feed and carriage return at the end of a line. In other words, these two method calls
System.out.print("Line 1");
System.out.print("Line 2");
produce this output
Line1Line2
Therefore, the previous for loop will produce this output:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Notice the following points about the for loop:
If you wanted to print five lines of this output, couldn't you place the previous for statement inside another for statement that iterates from 1 to 5? The following nested for loop does just that:
for (count = 1; count <= 5; count++ )
{ for (num=1; num<=10; num++)
{ System.out.print( num + ", "); }
}
The outer for loop is said to move more slowly than the inner loop. Before count moves from 1 to 2, the inner for loop iterates a full ten times. When the outer loop increments count to 2, the inner loop performs its complete cycle once more, going from 1 to 10.
Java supports these two loop control modifying statements: break and continue. You've seen break. The switch statement uses break to keep from falling through subsequent case options. You can also place break in loops to break out of the loop earlier than the loop would normally terminate.
Use break to break out of a loop, a case, or even a block earlier than the normal termination. Consider the following code:
for (ctr = 1; ctr <= 10; ctr++)
{ System.out.print("\007"); // Ring the bell
break; // Whoa! Terminate this loop now!
}
Without the break, the code would beep 10 times. (The seventh ASCII character, '\007', is the bell character that beeps your computer's speaker when you "print" the character.) The break forces early termination of the loop, however. The loop iterates through one time, rings the bell, then the break statement breaks out of the current loop and the program continues at the first statement following the for loop's closing brace.
Generally, you'll not put break on a line by itself. Instead, you'll use an if to break only upon a certain condition. Therefore, the following code rings the bell ten times unless the user gets tired of the bell and requests that it stop:
System.out.println("I'll ring the bell ten times.");
for (ctr = 1; ctr <= 10; ctr++)
{ System.out.print("\007"); // Ring the bell
System.out.print("Do you want to continue? (Y/N) ");
System.in.read(ans); // Call a method that fills ans with an answer
if (ans == 'Y')
{ break; } // Terminate loop if the user requested it
}
break has a second form and it is this:
break label;
If you put a label after a break, Java not only breaks out of the current switch, loop, or block, but Java transfers program control to the label. (The label must reside inside the current scope. You'll learn about scope in chapter 12 "Working with Classes," but for now, you don't need to worry about this limitation.)
Instead of breaking out of a loop, continue forces a new iteration of the loop. You can place a continue statement inside any loop: do, while, or for. When control reaches the continue, even if additional logic exists in the loop body, the loop body terminates and goes back to the top of the loop to test for another iteration.
The following code never asks the user if she or he wants to continue!
System.out.println("I'll ring the bell ten times.");
for (ctr = 1; ctr <= 10; ctr++)
{ System.out.print("\007"); // Ring the bell
continue; // Go back to the top of the loop!!!
System.out.print("Do you want to continue? (Y/N) ");
System.in.read(ans); // Call a method that fills ans with an answer
if (ans == 'Y')
{ break; } // Terminate loop if the user requested it
}
The continue tells Java to ignore the rest of the loop body. Therefore, the body's execution terminates as soon as control reaches continue.
Obviously, you'll use a conditional continue, usually by placing continue after an if statement, so the loop does not continue every time the program runs. If you did not control the conditional execution of continue, there would be no use in coding the loop body that appears after continue because the code would never execute.
As with break, you can attach a label to continue as the following format shows:
continue label;
The labeled continue lets you continue the outer loop from within the inner loop when you nest loops. Without the label, an inner loop's continue would continue only the inner loop's iteration.
The goal of this chapter was to give you the commands you need to control your programs. You can now write a lot of program logic and your programs can make decisions based on data values.
Use the if statement when your program is to decide upon one of two courses of actions. The if-else lets you specify both courses of possible program flow. The switch statement works like an if on steroids in that the switch statement lets you select from a wide range of multiple-choice options and act upon the correct choice.
When you use procedures and methods, you take advantage of Java's detouring effect. You'll access libraries of procedures and methods, as well as write your own, that perform lots of work for you as long as you call the procedure properly. Sometimes, you'll seed a method or procedure by passing one or more data values inside the parameter list and sometimes you'll want the method to produce a value for you by filling up a variable that you pass in the parameter list.
Unlike the decision statements, the looping statements repeat a series of statements over and over. By looping, you can quickly iterate through a huge array or a series of calculations. Java supports several kinds of loops and you can often choose the one you like best because all loops perform similar iterations of code blocks.
If you need to modify the behavior of loops, use break and continue. Break terminates a loop early. continue forces an early but new iteration of the current loop.
In the next chapter, you will take your Java language knowledge further by learning how classes actually work. In addition, you'll see how you can add object-oriented programming features to your own programs.
Here are the points this chapter covered:
| Previous Chapter | Next Chapter |
| Table of Contents | Book Home Page |
| Que Home Page | Digital Bookshelf | Disclaimer |
To order books from QUE, call us at 800-716-0044 or 317-361-5400.
For comments or technical support for our books and software, select Talk to Us.
© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.