Chapter 2
An Introduction to Data and Control

Copyright © 2004 by Stuart Reges

2.1 Introduction

Now that you know something about the basic structure of Java programs, you are ready to start solving problems with some complexity. You will still be restricted to programs that produce output, but we will begin to explore some of the aspects of programming that require problem solving skills.

The first half of the chapter fills in three important areas. First, it examines expressions: how simple values are expressed in Java, particularly numeric data. Second, it discusses program elements called variables that can change in value as the program executes. Third, it details the workings of the print and println statements that produce output.

The second half of the chapter introduces your first control structure: the for loop. You use this structure to repeat actions in a program. This is useful whenever you find a pattern in a complex task like the creation of a complex figure, because you can use a for loop to repeat an action that creates a particular pattern. The challenge is finding each pattern and figuring out what repeated actions will reproduce it.

2.2 Data and Types

Programs manipulate information and information comes in many forms. Java is what we call a strongly typed language, which means that Java requires us to be very explicit about what kind of information we intend to manipulate. Everything that we manipulate in a Java program will be of a certain type and we will constantly find ourselves telling Java what types of data we intend to use.

A decision was made early in the design of Java to have two very different kinds of data: primitive data and objects. The designers admit that this decision was made purely on the basis of performance to make Java programs run faster. This is unfortunate because it means that we have to learn two sets of rules about how data works. But this is one of those times when you simply have to pay the price if you want to use an industrial strength programming language. To make this a little easier, we will study the primitive data types first in this chapter and then turn our attention to objects in chapter 3.

There are eight primitive data types in Java but we will explore only four of them. The four types we will explore are listed below.

Commonly Used Primitive Types in Java
Type Description Examples
int integers (whole numbers) 42, -3, 18, 20493, 0
double real numbers 7.35, 14.9, -19.83423
char single characters 'a', 'X', '!'
boolean logical values true, false

It may seem odd to have one type for integers and another type for real numbers. Isn't every integer a real number? The answer is yes, but these are fundamentally different types of numbers. The difference is so great that we make this distinction even in English. We don't ask, "How much sisters do you have?" or "How many do you weigh?" We realize that sisters come in discrete integer quantities (0 sisters, 1 sister, 2 sisters, 3 sisters, and so on) and we use the word "many" for integer quantities ("How many sisters do you have?"). Similarly, we realize that weight can vary by tiny amounts (175 pounds versus 175.5 pounds versus 175.25 pounds and so on) and we use the word "much" for these real-valued quantities ("How much do you weigh?").

In programming this distinction is even more important because integers and reals are represented in a different way in the computer's memory. Integers are stored exactly while reals are stored as approximations with a limited number of digits of accuracy. We will see that this leads to round-off errors when you use real values.

The name "double" for real values isn't very clear. It's an accident of history that we have this name in much the same way that we still talk about "dialing" a number on our telephones even though modern telephones don't have a dial. The C programming language introduced a type called "float" for storing real numbers (short for "floating point number"). But floats had limited accuracy and another type was introduced called "double," short for "double precision" (double the precision of a simple float). As memory has become cheaper, people have moved more towards using double as the default for floating-point values. In hindsight, it might have been better to use the word "float" for what is now called double and then used a word like "half" for the values with less accuracy, but it's tough to change habits that are so ingrained. So programming languages will continue to use the word "double" for floating point numbers and people will still talk about dialing people on the phone even if they've never touched a telephone dial.

You might be wondering about the other four primitive types that weren't in the table above. They are simply variations of these more commonly used types. Below is a table of all eight of the primitive types with a short description of each.

Java Primitive Types
Type Description
float 32-bit real
double 64-bit real
byte 8-bit integer
short 16-bit integer
int 32-bit integer
long 64-bit integer
char 16-bit character
boolean logical values

2.3 Expressions

In Java, you refer to values by using an expression.

Expression

A description of how to obtain a value.

Suppose, for example, that you want to know how many bottles of water you have. If you have two 6-packs, four 4-packs and 2 individual bottles, then you could compute the total number of bottles with the following expression:

        (2 * 6) + (4 * 4) + 2
Notice that we use the asterisk to represent multiplication and that we use parentheses to group parts of the expression. The computer determines the value of an expression by evaluating it.

Evaluation

The process of obtaining the value of an expression.

The value obtained when an expression is evaluated is called the result.

Complex expressions are formed using operators. An operator is a special symbol (like "+" or "*") used to indicate an operation to be performed on one or more values. The values used in the expression are called operands. For example, consider the following simple expressions:

        3 + 29
        4 * 5
The operators here are the "+" and "*" and the operands are simple numbers:

           3        +        29
           |        |         |
        operand  operator  operand

           4        8         5
           |        |         |
        operand  operator  operand
When you form complex expressions, these simpler expressions can in turn become operands for other operators. For example, consider the following expression:

        (3 + 29) - (4 * 5)
Which has two levels of operators:

          (3        +        29)     -      (4        *         5)
           |        |         |      |       |        |         |
        operand  operator  operand   |    operand  operator  operand
           |                  |      |       |                  |
           +------------------+      |       +------------------+
                 operand          operator          operand
The plus operator has simple operands of 3 and 29 and the times operator has simple operands of 4 and 5, but the minus operator has operands that are each parenthesized expressions with operators of their own. Thus, complex expressions can be built from smaller expressions. At the lowest level you have simple numbers. These are used as operands to make more complex expressions, which in turn can be used as operands in even more complex expressions.

You will see many different operators as you progress through the book, all of which can be used to form expressions. Expressions can be arbitrarily complex, with as many operators as you like. For that reason, when I tell you, "An expression can be used here," I will often point out that I mean "arbitrary expressions" to emphasize that you can use complex expressions as well as simple values.

2.3.1 Literals

The simplest expressions refer to values directly using what are known as literals. An integer literal (considered to be of type int) is a sequence of digits with or without a leading sign:

        3    482    -29434    0    92348    +9812
A floating point literal (considered to be of type double) will include a decimal point, as in:

        298.4    0.284    207.    .2843    -17.452    -.98
Floating point literals can also be expressed in scientific notation (a number followed by "e" followed by an integer) as in:

        3.84e92    1e-5    2.458e12
The first value above represents 3.84 times 10 to the 92nd power. The second number represents 10 to the -5 power. The third represents 2.458 times 10 to the 12th power.

Character literals (of type char) are enclosed in single quotation marks and can include just one character:

         'a'    'm'    'X'    '!'    '3'    '\\'
All of these are of type char. Notice that the last example uses an escape sequence to represent the backslash character. You can even refer to the single quotation character using an escape sequence:

       '\''
The primitive type boolean has just two literals:

        true    false

2.3.2 Arithmetic Operators

The basic arithmetic operators are as follows.

Arithmetic Operators in Java
Operator Meaning Example Result
+ addition 2 + 2 4
- subtraction 53 - 18 35
* multiplication 3 * 8 24
/ division 4.8 / 2.0 2.4
% remainder or mod 19 % 5 4

The addition and subtraction operators should be familiar to you. The asterisk as a multiplication operator might be a surprise for nonprogrammers but doesn't take long to get used to. Division is also fairly familiar, although as we'll see, there are really two different division operations. The remainder or mod operation is the one that will be most unfamiliar to people.

Division presents a problem in the domain of integers. When you divide 119 by 5, for example, you do not get an integer. Therefore, integer division is expressed as two different integers--a quotient and a remainder:

        119
        ---  =  23 (quotient) with 4 (remainder)
         5
In terms of the arithmetic operators:

        119 / 5 evaluates to 23
        119 % 5 evaluates to  4
If you remember long-division, you remember doing calculations like this:

               31
           _______
        34 ) 1079
             102
             ----
               59
               34
               --
               25
Here, dividing 1079 by 34 yields 31 with a remainder of 25. Using arithmetic operators, the problem would be described like this:

        1079 / 34 evaluates to 31
        1079 % 34 evaluates to 25
For floating point values (values of type double) the division operator does what we consider "normal" division. So even though the expression 119/5 evaluates to 23, the expression 119.0/5.0 evaluates to 23.8. The remainder operator can be used with doubles as well as with ints and it has a similar meaning. You consider how much is left over when you take away as many "whole" values as you can. For example, the expression 10.2 % 2.4 evaluates to 0.6 because you can take away four 2.4's from 10.2, leaving you with 0.6 left over.

2.3.3 Precedence

Java expressions are like complex noun phrases in English. Such phrases are subject to ambiguity, as in, "the man on the hill by the river with the telescope." Is the river by the hill or by the man? Is the man holding the telescope, or is the telescope on the hill, or is the telescope in the river? You don't know how the various parts are grouped together.

You can get the same kind of ambiguity if parentheses aren't used to group the parts of a Java expression. For example, the expression 2 + 3 * 4 has two operators. Which is performed first? You could interpret this two ways:

        (2 + 3) * 4 = 6 * 4 = 24
        2 + (3 * 4) = 2 + 12 = 14
The first of these evaluates to 20 while the second evaluates to 14. To deal with the ambiguity, Java has rules of precedence that determine how the various parts are grouped together.

Precedence

The relative importance of one operator over another.

Rules of precedence are applied when the grouping of operators in an expression is ambiguous. An operator with low precedence is evaluated after operators of higher precedence. Within a given level of precedence the operators are evaluated in one direction, usually left to right.

For arithmetic expressions there are two levels of precedence. The multiplicative operators (*, /, %) have a higher level of precedence than the additive operators (+, -). So the expression 2 + 3 * 4 is interpreted as:

        2 + 3 * 4 = 2 + (3 * 4) = 2 + 12 = 14
Within the same level of precedence, arithmetic operators are evaluated from left to right. This often doesn't make a difference in the final result, but occasionally it does. Consider, for example:

        40 - 25 - 9 = (40 - 25) - 9 = 15 - 9 = 6
We will see many operators in the next few chapters. Below is a precedence table for many of the operators we will be working with. Obviously you won't understand what most of these do, but you might find yourself wanting to refer back to this table as you learn more and more of these. Higher in this table means higher in precedence.

Java Operator Precedence
Description Operators
unary operators !, ++, --
multiplicative operators *, /, %
additive operators +, -
relational operators <, >, <=, >=
equality operators ==, !=
logical and &&
logical or ||
assignment operators =, +=, -=, *=, /=, %=, &&=, ||=

2.3.4 Mixing Types, Conversion and Casting

We often find ourselves mixing values of different types and wanting to convert from one type to another. Java has simple rules that avoid confusion and provides a mechanism for requesting that a value be converted from one type to another.

We often find ourselves mixing ints and doubles. We might, for example, ask Java to compute 2 * 3.6. This involves the integer literal 2 and the floating point literal 3.6. In this case Java converts the integer into a floating point and performs this computation entirely in floating point. If Java encounters an int where it was expecting a double, it always converts the int to a double.

This becomes particularly important when you form expressions that involve division. If the two operands are both of type int, then Java will use integer (truncated) division. If either of the two operands is of type double, however, then it will do real-valued (normal) division. For example, 23 / 4 evaluates to 5 but all of the following evaluate to 5.75: 23.0 / 4, 23. / 4, 23 / 4.0, 23 / 4., 23. / 4., 23.0 / 4.0.

Sometimes you want Java to go the other way, converting a double into an int. You can ask Java to do this with what is known as a cast. Think of it as "casting a value in a different light." You request a cast by putting the name of the type you want to cast to in parentheses in front of the thing you want to cast. For example, if you say:

        (int)4.75
you will get the integer 4. When you cast a double value to an int it simply truncates anything after the decimal point. If you want to cast the result of an expression, you have to be careful to use parentheses. For example, suppose that you have some books that are 0.15 feet wide and you want to know how many of them would fit in a bookshelf that is 2.5 feet wide. You could do a straight division of 2.5 / 0.15, but that returns a floating point result of 16 and change. You don't care about the change. You want to compute the 16 part. You might form the following expression:

       (int)2.5 / 0.15
but this returns the wrong answer. That's because the cast is applied to whatever comes right after it, which is the value 2.5. So this casts 2.5 into the integer 2, divides by 0.15 and returns 13 and change, which isn't an integer and isn't the right answer. You want to form this expression:

        (int)(2.5 / 0.15)
This performs the division first to get 16 and change and then it casts that value to an int by truncating and returns the int value 16, which is the answer you're looking for.

In a later chapter we will explore the details of type char and we will see that every character has a corresponding integer value. Java is willing to automatically convert a value of type char into an int whenever it is expecting an int. For example, you can form the following rather strange expression:

        2 * 'a'
Java sees a value of type char where it was expecting an int, but it's happy to convert this for you, substituting the integer value 97 for 'a' and computing the result as 184.

Java will not, however, automatically convert in the other direction. That is because the type char is in a sense a subset of the type int. Every char value has a corresponding int, but not every int has a corresponding char. That means that Java would always be able to turn a char into an int, but might not always be able to turn an int into a char. So in this case Java insists on a cast. This allows you to form expressions like the following:

    (char)('a' + 3)
Inside the parentheses we have a combination of a char value and an int value, so Java converts the char to an int (95) and then performs the addition operation, yielding the value 98. This integer is then converted to a char value because of the cast, which yields the character 'd' (the character that appears 3 later in the sequence than the character 'a'). This turns out to be a useful kind of expression to form, as we'll see in a later chapter.

2.4 Variables

Primitive data can be stored in the computer's memory in a variable.

Variable

A memory location with a name and a type that stores a value.

As with all Java words, variables are named by legal identifiers. Java is particular about the type of each object, so you must tell the computer the type of every variable you plan to use. Every variable has a memory location set aside where it stores its value. Values can change, but only one value can be stored at a time. When the variable changes, the old value goes away.

All variables must be declared by specifying their type and name, as in:

    int x;
You put the name of the type followed by the name of the variable and you use a semicolon at the end to separate this declaration from other parts of the program. If you have several variables of the same type, you can list their names separated by commas after the type name, as in:

      int x, y, z;
You are allowed to initialize variables when they are declared by adding an equals and an expression after the variable name, as in:

       int x = 3;
or with multiple values:

        int x = 3, y = 5, z = 19;
Java requires that all variables be initialized before they are used, so it is a good idea to use this form rather than the simple declaration if you have some initial value that is appropriate for the variable. You are allowed to use arbitrary expressions when initializing variables and you are also allowed to initialize some of the variables while not initializing others, as in:

        int x = 2 + 3 * 4, y, z = 178 / 4 % 3;
Variable declarations are allowed inside curly braces where a statement would appear.

2.4.1 Assignment Statement

The simplest way to give a value to a variable is to use an assignment statement:

        first = 47;
This statement stores the value 47 in the memory location for the variable first. The general syntax of the statement is:

<variable> = <expression> > When the statement executes, the computer first evaluates the expression on the right side; then, it stores the result in the memory location for the given variable. The type of the variable and expression must match or must be compatible. The following assignment statement involves a more complex expression:

        second = 37 - 18 + 3;
Here, arithmetic operators form an expression of type int. The expression evaluates to 22, giving the value 22 to the variable second. Expressions need not contain only literals:

         sum = first + second;
To calculate the value of this expression, the computer adds together the current values of the variables first and second and comes up with the answer 69. This value is stored in the variable sum.

Even though Java uses the equals sign for assignment, don't confuse this with a statement of equality. This is a command to perform an action. For example, this is not a legal assignment statement:

        47 = first;
This does not fit the template. The left side must be a variable and in this statement the left side is an integer literal.

The assignment statement does not represent an algebraic relationship. In algebra if you say something like:

        x = y + 2
you are saying something very different from a statement like:

        second = first + 2;
When you say that x is equal to y plus 2, you are stating a fact for now and forever. If x changes, y will change accordingly. The assignment statement, on the other hand, is a command to perform an action at some moment in time. It does not represent a lasting relationship between variables. Consider this short program:

public class Sample { public static void main(String[] args) { int first, second; first = 13; second = first + 2; first = 50; System.out.println(first); System.out.println(second); } } This program outputs the values 50 and 15, which obviously don't have the algebraic relationship that one is 2 more than the other. Let's see why.

Initially first and second are uninitialized:

              +---+                    +---+
        first | ? |             second | ? |
              +---+                    +---+
The first assignment statement gives an value to the variable first:

              +----+                   +---+
        first | 13 |            second | ? |
              +----+                   +---+
and the second gives an initial value to the variable second:

              +----+                   +----+
        first | 13 |            second | 15 |
              +----+                   +----+
While there now exists an algebraic relationship between first and second similar to x = y + 2, this relationship is temporary because the third assignment statement reassigns the value of first:

              +----+                   +----+
        first | 50 |            second | 15 |
              +----+                   +----+
The variable second is no longer 2 more than first. The last assignment statement wipes out the old value of first and leaves second unchanged. This temporary quality of the assignment statement is sometimes difficult for beginners to grasp. Remember that in algebra one reasons about permanent relationships, whereas in programming one reasons about sequences of actions. The best habit to get into is to read the assignment statements equals sign as "gets" or "becomes."

One very common assignment statement that points out the difference between algebraic relationships and program statements is:

        first = first + 1;
This statement says, "first gets the value of first plus one." This may seem a rather odd statement, but you should be able to decipher it given the rules outlined above. Suppose that the current value of first is 19. To execute the statement, you first evaluate the expression to obtain the result 20. The computer stores this value in the variable named on the left, in variable first. Thus, this statement increments the value of first by one.

This section is titled "assignment statement" but in fact assignment is an operator, not a statement. That means that you can form expressions that have assignment operators embedded within them. Unlike most other operators, the assignment operator evaluates from right to left. This allows programmers to write statements like the following:

        int x, y, z;
        x = y = z = 2 * 5 + 4;
Because the assignment operator evaluates right-to-left, this is equivalent to: rightmost assignment:

        x = (y = (z = 2 * 5 + 4));
The expression evaluates to 14 which is assigned to the variable z. This expression itself evaluates to 14 and we move on to the next assignment:

        x = (y = 14);
This sets y to 14 and returns the value 14. Then we assign x the value 14. Notice that the parentheses aren't required. I've included them here to indicate more clearly the order in which the parts are evaluated.

While you can do assignments like these, it's not clear that you really want to do assignments like these. The chained assignment statement is fairly easy to read, but try to figure out what the following statement does:

        x = 3 * (y = 2 + 2) / (z = 2);
It's easier to see what is going on when you write this as three separate statements:

        y = 2 + 2;
        z = 2;
        x = 3 * y / z;

2.4.2 Other Operators

In addition to the standard assignment operator, Java has several special operators that are useful for a particular family of operations that are common in programming. You often find yourself increasing a variable by a particular amount which we call incrementing. You also often find yourself decreasing a variable by a particular amount, which we call decrementing. To accomplish this you write statements like the following:

        x = x + 1;
        y = y - 1;
        z = z + 2;
You also often find yourself wanting to double or triple a variable or to reduce its value by a factor of 2, in which case you might write code like the following:

        x = x * 2;
        y = y * 3;
        z = z / 2;
Java has a shorthand for these situations. You glue together the operator character (+, -, *, etc) with the equals to get a special assignment operator (+=, -=, *=, etc). This allows you to rewrite assignments statements like the ones above as follows:

        x += 1;
        y -= 1;
        z += 2;

        x *= 2;
        y *= 3;
        z /= 2;
This is yet another detail to learn about Java, but the code can be clearer to read. Think of a statement like "x += 2" as saying "add 2 to x." That's more concise than saying "x = x + 2."

Java has an even more concise way of expressing this for the particular case where you want to increment by 1 or decrement by 1 in which case you can use the operators "++" and "--". For example, you can say:

        x++;
        y--;
There are actually two different forms of each of these because you are also allowed to put the operator in front of the variable:

        ++x;
        --y;
The two versions of "++" are known as the pre-increment (++x) and post-increment (x++) operators. The two versions of "--" are similarly known as the pre-decrement (--x) and post-decrement (x--) operators. The pre versus post distinction doesn't matter when you include them as statements by themselves, as in these two examples. The difference comes up when you embed these inside of more complex expressions. The post versions return the old value of the variable, the value it had before the operation was performed. The pre versions return the new value of the variable, the value it has after the operation is performed.

Consider, for example, the following code fragment:

        int x = 10;
        int y = 20;
        int z = ++x * y--;
What value is z assigned? The answer is 220. The third assignment increments x to 11 and decrements y to 19, but in computing its own value it uses the new value of x (++x) times the old value of y (y--), which is 11 times 20 or 220.

There is a simple mnemonic to remember this. When you see "x++" read it as "give me x, then increment" and read "++x" as "increment, then give me x." Here's another memory device that might help. Just remember that C++ is a bad name for a programming language. The expression "C++" would be interpreted as, "Return the old value of C and then increment C." In other words, even though you're trying to come up with something new and different, you're really stuck with the old awful language. The language you want is ++C, because then you'd improve the language and you'd get to work with the new and improved language rather than the old one. Some people have suggested that perhaps Java is ++C.

The "++" and "--" operators were first introduced in the C programming language. Java has them because the designers of the language decided to use the syntax of C as the basis for Java syntax. Many languages have made the same choice, including C++ and C#. There is almost a sense of pride among C programmers that these operators allow you to write extremely concise code. Many other people feel that they can make code unnecessarily complex. In this book you will see that I almost always use these operators as a separate statement so that it is obvious what is going on.

2.4.3 Output and Strings Revisited

You saw in chapter 1 that you can output string literals using System.out.println. You can also output numeric expressions using System.out.println:

        System.out.println(12 + 3 - 1);
This statement causes the computer to first evaluate the expression, which yields the value 14, and then to write 14 to the console window. Often you want to output more than one value on a line. Unfortunately, you can only pass one value to println. To get around this, Java provides a simple mechanism called "concatenation" for putting several pieces together into one long string literal. The plus operator is used to concatenate the pieces together.

Consider, for example, the following program that computes the number of hours, minutes and seconds in a standard year.

public class Time { public static void main(String[] args) { int hours = 365 * 24; int minutes = hours * 60; int seconds = minutes * 60; System.out.println("Total hours in a year = " + hours); System.out.println("Total minutes in a year = " + minutes); System.out.println("Total seconds in a year = " + seconds); } } Notice that the three println commands at the end each have a string literal concatenated with a variable. The program produces the following output.

Total hours in a year = 8760 Total minutes in a year = 525600 Total seconds in a year = 31536000 You can use concatenation to form arbitrarily complex expressions. For example, if you had variables x, y and z and you wanted to write them out in coordinate format with parentheses and commas you could say:

        System.out.println("(" + x + ", " + y + ", " + z + ")");
If x, y and z have the values 8, 19 and 23, respectively, then this statement would output the string "(8, 19, 23)".

2.4.4 Print versus Println

Java has a variation of the println command called print that allows you to produce output on the current line without going to a new line of output. The println command really does two different things: it sends output to the current line and then it positions to the beginning of a new line. The print command does only the first of these. Thus, a series of print commands will generate output all on the same line. Only a println command will cause the current line to be completed and a new line to be started. For example, consider these six statements:

        System.out.print("Hi Ho, ");
        System.out.print("my man.");
        System.out.print("Where are you bound?  ");
        System.out.println("My way, I hope.");
        System.out.print("This is");
        System.out.println(" for the whole family!")
These statements produce two lines of output. Remember every println statement produces exactly one line of output. Because there are two println statements here, there are two lines of output. After the first statement executes, the current line looks like this:

        Hi ho,
               ^
The arrow below the output line indicates the position of the output cursor. It is at the end of this line. Notice that it is preceded by a space. That is because the string literal in the print command ends with a space. Java will not insert a space for you unless you specifically request it. After the next print, the line looks like this:

        Hi ho, my man.
                      ^
The output cursor doesn't have a space before it now because the string literal in the print command ends in a period, not a space. After the next print, the line looks like this:

        Hi ho, my man.Where are you bound?
                                            ^
There is no space between the period and the word "Where" because there was no space in the print commands. But the string literal in the third statement has spaces at the end and as a result the output cursor is positioned two spaces after the question mark. After the next statement executes, the output looks like this:

        Hi ho, my man.Where are you bound?  My way, I hope.

        ^
Because this fourth statement is a println command, it finishes the output line and positions the cursor at the beginning of the second line. The next statement is another print that produces this:

        Hi ho, my man.Where are you bound?
        This is
               ^
The final println completes the second line and positions the output cursor at the beginning of a new line:

        Hi ho, my man.Where are you bound?
        This is for the whole family!

        ^
These six statements are equivalent to these two single statements:

        System.out.println("Hi ho, my man.Where are you bound?  My way, I hope.");
        System.out.println("This is for the whole family!")
It seems a bit silly to have both the print and the println commands for producing lines like these, but you will see that there are more interesting applications of print.

It is possible to have empty println command:

        System.out.println();
Because there is nothing inside of parentheses to be written to the output line, this positions the output cursor to the beginning of the next line. If there are print commands before this empty println, it finishes out the line made by those print commands. If there are no previous print commands, it produces a blank line. An empty print command is meaningless and is illegal.

2.5 The For Loop

Programming often involves specifying redundant tasks. The for loop helps to avoid such redundancy. Suppose you want to write out the squares of the first 5 integers. You can say:

public class WriteSquares { public static void main(String[] args) { System.out.println(1 + " squared = " + (1 * 1)); System.out.println(2 + " squared = " + (2 * 2)); System.out.println(3 + " squared = " + (3 * 3)); System.out.println(4 + " squared = " + (4 * 4)); System.out.println(5 + " squared = " + (5 * 5)); } } This produces the following output:

1 squared = 1 2 squared = 4 3 squared = 9 4 squared = 16 5 squared = 25 This is a tedious solution to the problem. The program has five statements that are very similar. They are all of the form:

        System.out.println(number + " squared = " + (number * number));
where Number is either 1, 2, 3, 4, or 5. The for loop allows you to avoid such redundancy. Here is an equivalent program using a for loop:

public class WriteSquares2 { public static void main(String[] args) { for (int i = 1; i <= 5; i++) System.out.println(i + " squared = " + (i * i)); } } This program initializes a variable called i to the value 1. Then it repeatedly executes the println statement as long as the variable i is less than or equal to 5. After each println, it evaluates the expression i++ to increment i.

The general syntax of the for loop is as follows:

for (<initialization>; <test>; <update>) <statement> You always include the keyword "for" and the parentheses. Inside the parentheses you have three different parts separated by semicolons. The semicolons also must always appear. Java performs whatever initialization you have requested before the loop begins executing. Then it repeatedly performs the test you have provided. If the test returns true, then it executes the statement once and evaluates the update part. Then it performs the test again and if it again returns true, it executes the statement again and evaluates the update again.

The for loop is the first example of a control structure, a syntactic structure that controls another statement. Java allows great flexibility in deciding what to include in the initialization part and the update and this allows us to use the for loop to solve all sorts of programming tasks. For right now, we will restrict ourselves to a particular kind of loop that declares and initializes a single variable that is used to control the loop. This variable is often referred to as the control variable of the loop. In the test we compare the control variable against some final desired value and in the update we change the value of the control variable, most often incrementing it by 1. Such loops are very common in programming. By convention, we often use variable names like i, j and k for such loops.

Each execution of the controlled statement of a loop is called an iteration of the loop, as in, "The loop halted after four iterations." Iteration also refers to looping in general, as in, "I solved the problem using iteration."

Consider another for loop:

        for (int i = -100; i <= 100; i++)
            System.out.println(i + " squared = " + (i * i));
This loop executes a total of 201 times producing the squares of all the integers between -100 and +100 inclusive. The values used in the initialization and the test, then, can be any integers. They can, in fact, be arbitrary integer expressions:

        for (int i = (2 + 2); i <= (17 * 3); i++)
            System.out.println(i + " squared = " + (i * i));
This loop will generate the squares between 4 and 51 inclusive. The parentheses around the expressions are not necessary, but improve readability. Consider the following loop:

        for (int i = 1; i <= 30; i++)
            System.out.println("+--------+")
This loop generates 30 lines of output, all exactly the same. This loop is slightly different from the previous one because the statement controlled by the for loop makes no reference to the control variable. Thus:

        for (int i = -30; i <= -1; i++)
            System.out.println("+--------+")
generates exactly the same output. The behavior of such a loop is determined solely by the number of iterations it performs. The number of iterations is given by:

        (ending value) - (starting value) + 1
It is much simpler to see that the first of these loops iterates 30 times, so it is better to use the simpler form. In general, if we want a loop to iterate exactly n times, we will use one of two standard loops. The first standard form looks like the ones we have seen above:

for (int <variable> = 1; <variable> <= n; i++) <statement>; It's pretty clear that this loop executes n times because it starts at 1 and continues as long as it is less than or equal to n. Often, however, it is more convenient to start our counting at 0 instead of 1. That requires a change in the loop test to allow us to stop when n is 1 less:

for (int <variable> = 0; <variable> < n; i++) <statement>; Notice that in this form when we initialize the variable to 0, we test whether it is strictly less than n. Either form will execute exactly n times, although we will see some situations where the 0-based loop works better.

Let's consider some borderline cases. What happens if you say:

        for (int i = 1; i <= 1; i++)
            System.out.println("+--------+")
According to our rule, it should iterate once and it does. It initializes the variable i to 1 and tests to see if this is less than or equal to 1, which it is. So it executes the println, increments i and tests again. The second time it tests, it finds that i is no longer less than or equal to 1, so it stops executing. What about this loop:

        for (int i = 1; i <= 0; i++)
            System.out.println("+--------+")
This loop performs no iterations at all. It will not cause an execution error; it will merely not execute the controlled statement. The variable is initialized to 1 and we test to see if it is less than or equal to 0. It isn't, so we don't execute the controlled statement at all.

2.5.1 Controlling Multiple Statements

What if you want to write a for loop that executes two statements? What if, for example, you want to produce 20 pairs of lines, the first of which has the word "hi" on it and the second of which has the word "ho"? You might try the following:

        for (int i = 1; i <= 20; i++)
            System.out.println("Hi!");
            System.out.println("Ho!");
The indentation here indicates that you want both println statements to be controlled by the for loop. However, this indentation means nothing to the computer. The for loop controls whatever single statement follows the parentheses, no matter how you indent the program. So the fragment above produces 21 lines of output: 20 lines of "Hi!" followed by 1 line of "Ho!".

You could define a static method called twoLines that performs these two printlns and could then call the method as the one statement in the for loop:

        for (int i = 1; i <= 20; i++)
            twoLines();
However, there is another way to do this. You can turn a series of statements into a single statement by defining a block. A block is a series of statements separated by semicolons and enclosed in curly braces. The following syntax template illustrates the syntax of a block:

{ <statement or variable declaration>; <statement or variable declaration>; . . . <statement or variable declaration>; } The block statement groups statements and variable declarations so that they behave syntactically like a single statement. Thus, to make your for loop execute both println statements, you could use the following:

        for (int i = 1; i <= 20; i++) {
            System.out.println("Hi!");
            System.out.println("Ho!");
        }
The correct syntactic interpretation of this fragment is that the for loop controls a single statement, a block statement. However, the block statement has within it two println statements. So the loop is, in effect, controlling two statements. You can put as many statements as you like inside the curly braces:

        for (int i = 1; i <= 20; i++) {
            System.out.println("Hi!");
            System.out.println("Ho!");
            System.out.println("My");
            System.out.println("Man!")
        }
As always, you must be careful to separate the statements by semicolons. We are once again using the standard Java convention of putting the open curly brace at the end of the line with the for statement on it. Some people prefer to have it at the beginning of the next line:
        for (int i = 1; i <= 20; i++)
        {
            System.out.println("Hi!");
            System.out.println("Ho!");
            System.out.println("My");
            System.out.println("Man!")
        }

2.5.2 For Loops within For Loops

The for loop controls a statement, and the for loop is itself a statement. This makes the following legal:

        for (int i = 1; i <= 10; i++)
            for (int j = 1; j <= 5; j++)
                System.out.println("Hi there.");
This is probably easier to read from the inside out. The println statement produces a single line of output. The j loop executes this statement 5 times, producing 5 lines of output. The outer loop executes the inner loop 10 times, which produces 10 sets of 5 lines, or 50 lines of output. The code above, then, is equivalent to:

        for (int i = 1; i <= 50; i++)
            System.out.println("Hi there.");
This example shows that a for loop can be controlled by another for loop. Such a loop is called a nested loop. Look at another nested loop. Consider how to generate a single line of output with 30 asterisks on it. You could do the following:

        System.out.println("******************************");
This solution is not very adaptable or readable. It isn't immediately obvious how many asterisks are being written out, nor is it simple to change that number. There is a better way. You can use a loop to write the 30 asterisks:

        for (int column:= 1; column <= 30; column++)
            System.out.print("*");
        System.out.println();
We use print instead of println to output the asterisks on one line. You follow this with an empty println to finish the line of output. This solution is more readable and is more easily changed to produce a line of different length. This code produces a single line. If you want to produce 50 lines, you can nest these statements inside another loop. The following fragment produces 50 lines of output, each with 30 asterisks on it.

        for (int row = 1; row <= 50; row++) {
            for (int column= 1; column <= 30; column++)
                System.out.print("*");
            System.out.println();
        }

2.5.3 Levels of Control

Block statements and control structures introduce different statement levels, the relative levels of control of statements within a block:

In my indentation scheme, each level of indentation corresponds to one of these levels of structure. This allows me to visually scan the structure of a piece of code. Sometimes it is useful to actually annotate the program and list the level of each statement. For example, here is a listing of the loops examined in the last section. The level has been included as an extra column to the left of the code. Since curly braces are not statements, I don't assign them a level, but I include them in the level notation. This fragment has three levels of structure:

        1{       for (int row = 1; row <= 50; row++) {
        2            for (int column= 1; column <= 30; column++)
        3                System.out.print("*");
        2            System.out.println();
        }        }
Here is a more complicated program fragment with four levels of structure:

        1{       for (int row = 1; row <= 5; row++) {
        2{           for (int column = 1; column <= 15; column++) {
        3                System.out.print("|");
        3                for (int dashes = 1; dashes <= 3; dashes++)
        4                    System.out.print("-");
        }            }
        2            System.out.println();
        }        }
This fragment produces 5 rows each with 15 columns composed of a vertical bar and 3 dashes. Thus, the output of this code is:

|---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- |---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- |---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- |---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- |---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- There is no limit to the number of times you can nest one loop inside another, so your statement levels can be arbitrarily high.

2.5.4 Scope, Local Variables and Loops

Now that we are dealing with block statements and nested statements, we need to understand the concept of scope.

Scope of a declaration

The part of a program in which a particular declaration is valid.

We have seen that when it comes to declaring static methods, we can put them in any order whatsoever. The scope of a static method is the entire class in which it appears. Variables work differently. The simple rule is that the scope of a variable declaration extends from the point where it is declared to the end of the block enclosing the declaration. In other words, find the pair of curly braces that directly enclose the variable declaration. The scope of the variable is from the point where it is declared to the closing curly brace for that block.

There are several implications of this scope rule. Consider first what it means for different methods. Each method has its own set of curly braces to indicate the statements to be executed when the method is called. If variables are declared inside of a method's curly braces, then those variables won't be available outside the method. We refer to such variables as local variables and we refer to this process as localizing variables. We consider this a good programming practice. In general, we want to declare variables in the most local scope possible.

Local Variable

A variable declared inside a method that is accessible only in that method.

Localizing Variables

Declaring variables in the innermost (most local) scope possible.

You might wonder why we would want to localize variables to just one method. Why not just declare everything in one outer scope? That certainly seems simpler. The idea is similar to the use of refrigerators in dormitories. Every dorm room can have its own refrigerator for use in that room. If you are outside of a room, you don't even know that it has a refrigerator in it. The contents of the room are hidden from you.

Localizing variables leads to some duplication and confusion, but provides more security. Our programs use variables to store values just as students use refrigerators to store beer, ice cream, and other valuables. The last time I was in a dorm I noticed that most of the individual rooms had refrigerators in them. This seems terribly redundant, but the reason is obvious. If you want to guarantee the security of something, you put it where nobody else can get it. You will use local variables in much the same way. Each individual block will have its own local variables to use, which means you don't have to consider possible interference from other parts of the program.

Scope rules are important to understand when we talk about the local variables of one method versus another method, but they also have implications for what happens inside a single method. We have seen that curly braces can be used to form a special kind of statement called a block statement that can appear inside a method. By nesting blocks inside of blocks and declaring variables in those blocks, we generate different scopes. Consider the following method.

        public static void illegalScope() {
            int x = 3;
            {
                int y = 7;
                System.out.println("x = " + x + ", y = " + y);
            }
            System.out.println("x = " + x + ", y = " + y);
        }
This method won't compile. It declares a variable x whose scope is the entire method and a variable y whose scope is just the inner block. The innermost println (the first one) is not a problem because at that point both x and y are visible. The outer println (the second one) causes a problem because it refers to the variable y outside of the scope of the variable y.

There are a few special cases for scope and the for loop is one of them. When a variable is declared in the initialization part of a for loop, then its scope is just the for loop itself (the 3 parts in the for loop header and the statement controlled by the for loop). That means that you can use the same variable name in multiple for loops:

        for (int i = 1; i <= 10; i++)
            System.out.println(i + " squared = " + (i * i));
        for (int i = 1; i <= 10; i++)
            System.out.println(i + " cubed = " + (i * i * i));
The variable i is declared twice, but because the scope of each is just the for loop in which it is declared, this isn't a problem. This is like having two dorm rooms, each with its own refrigerator. Of course, we can't do this with nested for loops:

        for (int i = 1; i <= 5; i++)
            for (int i = 1; i <= 10; i++)
                System.out.println("hi there.");
This code won't compile. When Java encounters the inner for loop, it will complain that the variable i has already been declared within this scope. You aren't allowed to declare the same variable twice within the same scope. That would be like having two refrigerators in the same dorm room.

In all of the for loop examples we have looked at, the control variable is declared in the initialization part of the loop. This isn't a requirement. You can separate the declaration of the variable from the initialization of the variable, as in the following.

        int i;
        for (i = 1; i <= 5; i++)
            System.out.println(i + " squared = " + (i * i));
In effect, we have taken the "int i" part out of the loop itself and put it outside the loop. That means that its scope is greater than it was before. Its scope extends to the end of the enclosing block. One advantage of this approach is that we can refer to the final value of the control variable after the loop. Normally we wouldn't be able to do so because its scope would be limited to the loop itself. But this is a dangerous practice that you will generally want to avoid. It also provides a good example of the problems you can encounter when you don't localize variables. Consider the following code, for example:
        int i;
        for (i = 1; i <= 5; i++)
            for (i = 1; i <= 10; i++)
                System.out.println("hi there.");
As noted above, you shouldn't use the same control variable when you have nested loops. But unlike the previous example, this one actually compiles. So instead of getting a helpful error message from the Java compiler, you get a program with a bug in it. You'd think from reading these loops that it produces 50 lines of output but it actually produces just 10 lines of output. The inner loop increments the variable i until it becomes 11 and that causes the outer loop to terminate after just one iteration. It can be even worse. If you reverse the order of these loops:

        int i;
        for (i = 1; i <= 10; i++)
            for (i = 1; i <= 5; i++)
                System.out.println("hi there.");
You get something known as an "infinite loop." No matter what the outer loop does to the variable i, the inner loop always sets it back to 1 and iterates until it becomes 6. The outer loop finds that 6 is less than or equal to 10, so it always goes back to the inner loop which once again sets the variable back to 1 and iterates up to 6. This goes on indefinitely. These are the kinds of interference problems you can get when you fail to localize variables.

2.5.5 Programming with Pseudocode

The programs that you write describe a particular algorithm for solving a problem.

Algorithm

A precise step-by-step description of how to solve a problem.

As you develop more and more complex algorithms, you will want to make use of the technique of writing pseudocode.

Pseudocode

English-like descriptions of algorithms. Programming with pseudocode involves successively refining an informal description until it is easily translated into Java.

For example, you can describe the problem of drawing a box as:

        draw a box with 50 lines and 30 columns of asterisks.
While this describes the figure, it is not specific about how to draw it, what algorithm to use. Do you draw the figure line-by-line or column-by-column? In Java, figures like these must be generated line by line because once a println has been performed on a line of output, that line cannot be changed. There is no command for going back to a previous line in an output file. Therefore, the first line must be output in its entirety first, then the second line in its entirety, and so on. That means your decompositions for these figures will be line-oriented at the top level. Thus, a closer approximation is:

        for (each of 50 lines)
            draw a line of 30 asterisks.
Even this can be made more specific by introducing the idea of writing a single character on the output line versus moving to a new line of output:

        for (each of 50 lines) {
           for (each of 30 columns)
               write one asterisk on the output line.
           go to a new output line.
        }
Using pseudocode, you can gradually convert an English description into something easily translated into a Java program. The simple examples you have seen so far are hardly worth the application of pseudocode, so you will now examine the problem of generating a more complex figure:

********* ******* ***** *** * This figure must also be generated line by line:

        for (each of 5 lines)
            draw one line of the triangle.
Unfortunately, each line is different. Therefore, you must come up with a general rule that fits all lines. The first line of this figure has a series of asterisks on it with no leading spaces. The subsequent lines have a series of spaces followed by a series of asterisks. Using your imagination a bit, you can say that the first line has 0 spaces on it followed by a series of asterisks. This allows you to write a general rule for making this figure:

        for (each of 5 lines) {
            write some spaces (possibly 0) on the output line.
            write some asterisks on the output line.
            go to a new output line.
        }
In order to proceed, you must determine a rule for the number of spaces and a rule for the number of asterisks. Assuming that the lines are numbered 1 through 5 and looking at the figure, you can fill in the following chart:

Line Spaces Asterisks
109
217
325
433
541

You want to find a relationship between line number and the other two columns. This is simple algebra, because these columns are related in a linear way. The second column is easy to get from Line, it equals (line - 1). The third column is a little tougher. Because it goes down by 2 every time and the first column goes up by 1 every time, you need a multiplier of -2. Then you need an appropriate constant. The number 11 seems to do the trick, so that the third column equals (11 - 2 * line). You can improve your pseudocode, then, as follows:

        for line going 1 to 5 {
            write (line - 1) spaces on the output line.
            write (11 - 2 * line) asterisks on the output line.
            go to a new output line.
        }
This is simple to turn into a program:

public class DrawV { public static void main(String[] args) { for (int line = 1; line <= 5; line++) { for (int column = 1; column <= (line - 1); column++) System.out.print(" "); for (int column = 1; column <= (11 - 2 * line); column++) System.out.print("*"); System.out.println(); } } }

2.5.6 For Loop Variations

How would you produce this figure?

* *** ***** ******* ********* You could follow the same process you did above and find new expressions that produce the appropriate number of spaces and asterisks. However, there is an easier way. This figure is the same as the previous one, except the lines appear in reverse order. We can achieve this result by running the for loop backwards. So instead of starting at 1 and going up to 5 with a "++" update, we can start at 5 and go down to 1 using a "--" update. For example, the following loop:
        for (int i = 10; i >= 1; i--)
            System.out.println(i + " squared = " + (i * i));
will produce the squares of the first ten integers, but in reverse order. The simple way to produce the upward-pointing triangle, then, is:

public class DrawCone { public static void main(String[] args) { for (int line = 5; line >= 1; line--) { for (int column = 1; column <= (line - 1); column++) System.out.print(" "); for (int column = 1; column <= (11 - 2 * line); column++) System.out.print("*"); System.out.println(); } } } There are many variations on the basic for loop. For example, suppose that we want to write out the squares of the even numbers between 2 and 20. We could say:
        for (int i = 1; i <= 10; i++)
            System.out.println(2 * i + " squared = " + (2 * i * 2 * i));
Alternatively, we could have our control variable increase in value by 2 each time instead of increasing by 1 each time:
        for (int i = 2; i <= 20; i += 2)
            System.out.println(2 * i + " squared = " + (2 * i * 2 * i));

2.5.7 Magic Numbers

The DrawCone program in the last section draws a cone with 5 lines. How would you modify it to produce a cone with 3 lines? One simple strategy is to change all the 5's to 3's, which will produce this output:

          *****
         *******
        *********
This is obviously wrong. If you work through the geometry of the figure, you will discover that the problem is with the number 11 in one of the expressions. The number 11 comes from this formula:

        2 * (number of lines) + 1
Thus, for 5 lines the appropriate value is 11. But for 3 lines the appropriate value is 7. Programmers call numbers like these magic numbers. They are magic in the sense that they seem to make the program work, but their definition is not always obvious. Glancing at the program, one is apt to ask, "Why 5? Why 11? Why 3? Why 7? Why me?"

To make programs more readable and more adaptable, you should try to avoid magic numbers whenever possible. You do so by storing the magic numbers. You can use variables to store these values, but that is misleading, given that you are trying to represent values that don't change. Java offers an alternative. You can create objects that are guaranteed to have constant values. Not surprisingly, they are called "constants."

The first advantage of a constant is that you can name it. This allows you to choose a descriptive name that explains what the constant represents. You can then use that name instead of referring to the specific value to make your programs more readable and adaptable. For example, in the DrawCone program you might want to introduce a constant called LINES that will replace the magic number 5 (recall from chapter 1 that we use all uppercase letters for constant names). Also, you can use the constant as part of an expression to calculate a value. This allows you to replace the magic number 11 with a formula like (2 * LINES + 1).

Constants are declared with the keyword "final" which indicates the fact that their values cannot be changed once assigned. You can declare them anywhere you can declare a variable, as in:

        final int LINES = 5;
These values can be declared inside a method just like a variable, but they are often used by several different methods. As a result, we generally declare constants outside of methods. This causes us to have another run-in with our old pal the "static" keyword. If we want to declare a constant that our static methods can access, then the constant itself has to be static. And just as we declare our methods to be public, we usually declare our constants to be public. The general syntax for constant definitions appears below.

public static final <type> <identifier> = <expression>; For example, below are definitions for two constants.

        public static final int HEIGHT = 10;
        public static final int WIDTH = 20;
These definitions create constants called HEIGHT and WIDTH that will always have the values 10 and 20.

How would you rewrite the DrawCone program with a constant to eliminate the magic numbers? You would introduce a constant for the number of lines:

        public static final int LINES = 5;
Next, you replace the 5 in the outer loop with this constant. Then, you replace the 11 in the second inner loop with the expression (2 * LINES + 1). The result is the following program.

public class DrawCone2 { public static final int LINES = 5; public static void main(String[] args) { for (int line = LINES; line >= 1; line--) { for (int column = 1; column <= (line - 1); column++) System.out.print(" "); for (int column = 1; column <= (2 * LINES + 1 - 2 * line); column++) System.out.print("*"); System.out.println(); } } } The advantage of this program is that it is more readable and more adaptable. You can make a simple change to the constant LINES to make it produce a different size figure.

2.5.8 A Complex Figure

Now consider an example that is even more complex. To solve it, you will use static methods to decompose the task into subtasks. Consider the following figure:

+------+ |\ /| | \ / | | \/ | | /\ | | / \ | |/ \| +------+ In order to generate this figure, you have to first break it down into subfigures. In doing so, you should look for lines that are similar in one way or another. The first and last lines are exactly the same. The three lines after the first line all fit one pattern, and the three lines after that fit another. Thus, you can break the problem down as:

        draw a solid line.
        draw the top half of the hourglass.
        draw the bottom half of the hourglass.
        draw a solid line.
You should solve each independently. Before you do so, however, you should think a moment about possible magic numbers this figure might generate. It has a specific height and width that might introduce magic numbers. Because of the regularity of the figure, though, the height is determined by the width and vice versa. For example, if you change the height of the two hourglass halves from 3 to 4, you have to increase the overall width from 8 to 10 to make the diagonals line up properly. Therefore, you should define only one constant. Suppose you choose the height of the hourglass halves:

        public static final int SUB_HEIGHT = 3;
Notice how we use the underscore character to separate the different words in the name of the constant. Given this constant, you can calculate the other magic numbers that are related to size. For example, the overall width of the figure is:

        (2 * SUB_HEIGHT + 2)
And the number of dashes in a solid line is:

        (2 * SUB_HEIGHT)
Thus, you can use these expressions to avoid magic numbers. The solid line task can be further specified as:

        write a plus on the output line.
        write (2 * SUB_HEIGHT) dashes on the output line.
        write a plus on the output line.
        go to a new output line.
This translates easily into a static method:

    public static void drawLine() {
        System.out.print("+");
        for (int column = 1; column <= (2 * SUB_HEIGHT); column++)
            System.out.print("-");
        System.out.println("+");
    }
The top half of the hourglass is more complex. Here is a typical line:

        | \  / |
This has four printing characters and some spaces that separate them:

         |               \                /             |
        bar  spaces  backslash  spaces  slash  spaces  bar
Thus, a first approximation in pseudocode:

        for (each of SUB_HEIGHT lines) {
            write a bar on the output line.
            write some spaces on the output line.
            write a back slash on the output line.
            write some spaces on the output line.
            write a slash on the output line.
            write some spaces on the output line.
            write a bar on the output line.
            go to a new line of output.
        }
Again, you can make a table to figure out the desired expressions. Writing the single characters will be easy enough to translate into Java, but you need to be more specific about the spaces. This line really has three sets of spaces. Here is a table that shows how many to use in each case:

Line Spaces Spaces Spaces
1040
2121
3202

The first and third sets of spaces fit the rule (line - 1), and the second number of spaces is (6 - 2 * line). But how do you account for possible magic numbers? There are many ways to do so. You could find the expressions for different heights and see how they differ. Or you could analyze the geometry of the figure and try to deduce the expressions. Or you could guess and hope that you are right. Any of those solutions would inevitably lead to the conclusion that the only magic number in the expressions above is 6, which comes from (2 * SUB_HEIGHT). Thus, the correct expressions are: (line - 1) and 2 * (SUB_HEIGHT - line). Therefore, the pseudocode should read:

        for (line going 1 to SUB_HEIGHT) {
            write a bar on the output line.
            write (line - 1) spaces on the output line.
            write a back slash on the output line.
            write 2 * (SUB_HEIGHT - line) spaces on the output line.
            write a slash on the output line.
            write (line - 1) spaces on the output line.
            write a bar on the output line.
            go to a new line of output.
        }
This is easily translated into a static method. A similar solution exists for the bottom half of the hourglass. Put together, the program looks like this:

public class DrawFigure { public static final int SUB_HEIGHT = 3; public static void main(String[] args) { drawLine(); drawTop(); drawBottom(); drawLine(); } // Produces a solid line public static void drawLine() { System.out.print("+"); for (int column = 1; column <= (2 * SUB_HEIGHT); column++) System.out.print("-"); System.out.println("+"); } // This produces the top half of the hourglass figure public static void drawTop() { for (int line = 1; line <= SUB_HEIGHT; line++) { System.out.print("|"); for (int column = 1; column <= (line - 1); column++) System.out.print(" "); System.out.print("\\"); for (int column = 1; column <= 2 * (SUB_HEIGHT - line); column++) System.out.print(" "); System.out.print("/"); for (int column = 1; column <= (line - 1); column++) System.out.print(" "); System.out.println("|"); } } // This produces the bottom half of the hourglass figure public static void drawBottom() { for (int line = 1; line <= SUB_HEIGHT; line++) { System.out.print("|"); for (int column = 1; column <= (SUB_HEIGHT - line); column++) System.out.print(" "); System.out.print("/"); for (int column = 1; column <= 2 * (line - 1); column++) System.out.print(" "); System.out.print("\\"); for (int column = 1; column <= (SUB_HEIGHT - line); column++) System.out.print(" "); System.out.println("|"); } } } This solution may seem cumbersome, but it is easier to adapt to a new task. It would be simple, for example, to modify this program to produce the figure below. All you have to do is reverse the order of the calls on methods drawTop and drawBottom in the main method:

        +------+
        |  /\  |
        | /  \ |
        |/    \|
        |\    /|
        | \  / |
        |  \/  |
        +------+

2.5.9 Global Versus Local Constants

The program written in the last section raises an important issue. It declares a constant called SUB_HEIGHT that is used throughout the program. But the constant is not declared locally in the individual methods. That seems to violate our principle of localizing whenever possible. While localizing of variables is a good idea, the same, is not always true for constants. In this case a class-wide definition is more appropriate. We localize variables do avoid potential interference. That argument doesn't hold for constants, since they are guaranteed not to change. Another argument for using local variables is that it makes our static methods more independent. That argument has some merit, but not enough. It is true that global constants introduce dependencies between methods, but often that is really what you want. For example, the three methods of the hourglass program should not be independent of each other when it comes to the size of figures. Each subfigure has to use the same size constant. Imagine the potential disaster if each method had its own SUB_HEIGHT each with a different value. None of the pieces would fit together.

2.6 Programming Problems

  1. Write a program that produces the following output:

            ****** //////////// ******
            *****  //////////\\  *****
            ****   ////////\\\\   ****
            ***    //////\\\\\\    ***
            **     ////\\\\\\\\     **
            *      //\\\\\\\\\\      *
                   \\\\\\\\\\\\
    
  2. Write a program that produces the following output:

            +---------+
            |    *    |
            |   /*\   |
            |  //*\\  |
            | ///*\\\ |
            | \\\*/// |
            |  \\*//  |
            |   \*/   |
            |    *    |
            +---------+
            | \\\*/// |
            |  \\*//  |
            |   \*/   |
            |    *    |
            |    *    |
            |   /*\   |
            |  //*\\  |
            | ///*\\\ |
            +---------+
    
  3. Write a program that displays Pascal's triangle:

                                   1
                                 1   1
                               1   2   1
                             1   3   3   1
                           1   4   6   4   1
                         1   5  10  10   5   1
                       1   6  15  20  15   6   1
                     1   7  21  35  35  21   7   1
                   1   8  28  56  70  56  28   8   1
                 1   9  36  84 126 126  84  36   9   1
               1  10  45 120 210 252 210 120  45  10   1
    
  4. Write a program that produces the following output. Use a program constant to make it possible to change the number of stairs in the figure.

                                  O  *******
                                 /|\ *     *
                                 / \ *     *
                             O  ******     *
                            /|\ *          *
                            / \ *          *
                        O  ******          *
                       /|\ *               *
                       / \ *               *
                   O  ******               *
                  /|\ *                    *
                  / \ *                    *
              O  ******                    *
             /|\ *                         *
             / \ *                         *
            ********************************
    

    Stuart Reges
    Last modified: Fri Oct 1 15:03:41 PDT 2004