Saturday, January 7, 2012

chapter 3


Introduction to GUI Programming


FOR THE PAST TWO CHAPTERS, you've been learning the sort of programming that is done inside a single subroutine. In the rest of the text, we'll be more concerned with the larger scale structure of programs, but the material that you've already learned will be an important foundation for everything to come.
In this section, before moving on to programming-in-the-large, we'll take a look at how programming-in-the-small can be used in other contexts besides text-based, command-line-style programs. We'll do this by taking a short, introductory look at applets and graphical programming. The point here is not so much to understand GUI programming as it is to illustrate that a knowledge of programming-in-the-small applies to writing the guts of any subroutine, not just main().
An applet is a Java program that runs on a Web page. An applet is not a stand-alone application, and it does not have a main() routine. In fact, an applet is an object rather than a class. When Java first appeared on the scene, applets were one of its major appeals. Since then, they have become much less important, although they can still be very useful. When we study GUI programming in Chapter 6, we will concentrate on stand-alone GUI programs rather than on applets, but applets are a good place to start for our first look at the subject.
When an applet is placed on a Web page, it is assigned a rectangular area on the page. It is the job of the applet to draw the contents of that rectangle. When the region needs to be drawn, the Web page calls a subroutine in the applet to do so. This is not so different from what happens with stand-alone programs. When such a program needs to be run, the system calls the main() routine of the program. Similarly, when an applet needs to be drawn, the Web page calls a subroutine in the applet. The programmer specifies what happens when this routine is called by filling in the body of the routine. Programming in the small! Applets can do other things besides draw themselves, such as responding when the user clicks the mouse on the applet. Each of the applet's behaviors is defined by a subroutine. The programmer specifies how the applet behaves by filling in the bodies of the appropriate subroutines.
To define an applet, you need a class that is a subclass of the built-in class named Applet. To avoid some technicalities in this section as well as to make things a little more interesting, we will not work with theApplet class directly. Instead, we will work with I class that I wrote named AnimationBase, which is itself a subclass of AppletAnimationBase makes it easy to write simple animations. A computer animationis really just a sequence of still images, which are called the frames of the animation. The computer displays the images one after the other. Each image differs a bit from the preceding image in the sequence. If the differences are not too big and if the sequence is displayed quickly enough, the eye is tricked into perceiving continuous motion. To create the animation, you just have to say how to draw each individual frame. When using AnimationBase, you do that by filling in the inside of a subroutine named drawFrame(). More specifically, to create an animation using AnimationBase, you have write a class of the form:
import java.awt.*;
 
public class name-of-class extends AnimationBase {
 
    public void drawFrame(Graphics g) {
       statements
    }
    
}
where name-of-class is an identifier that names the class, and the statements are the code that actually draws the content of one of the frames of the animation. This looks similar to the definition of a stand-alone program, but there are a few things here that need to be explained, starting with the first line.
When you write a program, there are certain built-in classes that are available for you to use. These built-in classes include System and Math. If you want to use one of these classes, you don't have to do anything special. You just go ahead and use it. But Java also has a large number of standard classes that are there if you want them but that are not automatically available to your program. (There are just too many of them.) If you want to use these classes in your program, you have to ask for them first. The standard classes are grouped into so-called "packages." One of these packages is called "java.awt". The directive "import java.awt.*;" makes all the classes from the package java.awt available for use in your program. The java.awt package contains classes related to graphical user interface programming, including a class called Graphics. The Graphics class is referred to in the drawFrame() routine above and will be used for drawing the frame.
The definition of the class above says that the class "extends AnimationBase." The AnimationBase class includes all the basic properties and behaviors of applet objects (since it is a subclass of Applet). It also defines the basic properties and behaviors of animations -- it "extends" class Applet by adding in this extra stuff. When you extend AnimationBase, you inherit all these properties and behaviors, and you can add even more stuff, in particular the drawing commands that you want to use to create your animation.
(One more thing needs to be mentioned -- and this is a point where Java's syntax gets unfortunately confusing. You can skip this explanation until Chapter 5 if you want. Applets are objects, not classes. Instead of being static members of a class, the subroutines that define the applet's behavior are part of the applet object. We say that they are "non-static" subroutines. Of course, objects are related to classes because every object is described by a class. Now here is the part that can get confusing: Even though a non-static subroutine is not actually part of a class (in the sense of being part of the behavior of the class itself), it is nevertheless defined in a class (in the sense that the Java code that defines the subroutine is part of the Java code that defines the class). Many objects can be described by the same class. Each object has its own non-static subroutine. But the common definition of those subroutines -- the actual Java source code -- is physically part of the class that describes all the objects. To put it briefly: static subroutines in a class definition say what the class does; non-static subroutines say what all the objects described by the class do. The drawFrame() routine is an example of a non-static subroutine. A stand-alone program's main()routine is an example of a static subroutine. The distinction doesn't really matter too much at this point: When working with stand-alone programs, mark everything with the reserved word, "static"; leave it out when working with applets. However, the distinction between static and non-static will become more important later in the course.)

Let's write an applet based on AnimationBase. In order to draw the content, we'll need to know some basic subroutines that are already available for drawing, just as in writing text-oriented programs we need to know what subroutines are available for reading and writing text. In Java, the built-in drawing subroutines are found in objects of the class Graphics, one of the classes in the java.awt package. In our applet's drawFrame() routine, we can use the Graphics object g for drawing. (This object is provided as a parameter to the drawFrame() routine when that routine is called.) Graphics objects contain many subroutines. I'll mention just three of them here. You'll encounter more of them in Chapter 6.
  • g.setColor(c), is called to set the color that is used for drawing. The parameter, c is an object belonging to a class named Color, another one of the classes in the java.awt package. About a dozen standard colors are available as static member variables in the Color class. These standard colors include Color.BLACKColor.WHITEColor.REDColor.GREEN, and Color.BLUE. For example, if you want to draw in red, you would say "g.setColor(Color.RED);". The specified color is used for all subsequent drawing operations up until the next time setColor() is called.
  • g.drawRect(x,y,w,h) draws the outline of a rectangle. The parameters xyw, and h must be integers or integer-valued expressions. This subroutine draws the outline of the rectangle whose top-left corner is x pixels from the left edge of the applet and y pixels down from the top of the applet. The width of the rectangle is w pixels, and the height is h pixels. The color that is used is black, unless a different color has been set by calling setColor().
  • g.fillRect(x,y,w,h) is similar to drawRect except that it fills in the inside of the rectangle instead of just drawing an outline.
This is enough information to write the applet shown here:
Although the applet is defined as an animation, you don't see any movement because all the frames that are drawn are identical! This is rather silly, and we will fix it in the next example. But for now, we are just interested in seeing how to use drawing routines to draw a picture.
The applet first fills its entire rectangular area with red. Then it changes the drawing color to black and draws a sequence of rectangles, where each rectangle is nested inside the previous one. The rectangles can be drawn with a while loop, which draws the rectangles starting from the outside and moving in. Each time through the loop, the rectangle that is drawn is smaller than the previous one and is moved down and over a bit. We'll need variables to hold the width and height of the rectangle and a variable to record how far the top-left corner of the rectangle is inset from the edges of the applet. The while loop ends when the rectangle shrinks to nothing. In general outline, the algorithm for drawing the applet is
Set the drawing color to red  (using the g.setColor subroutine)
Fill in the entire applet (using the g.fillRect subroutine)
Set the drawing color to black
Set the top-left corner inset to be 0
Set the rectangle width and height to be as big as the applet
while the width and height are greater than zero:
    draw a rectangle (using the g.drawRect subroutine)
    increase the inset
    decrease the width and the height
In my applet, each rectangle is 15 pixels away from the rectangle that surrounds it, so the inset is increased by 15 each time through the while loop. The rectangle shrinks by 15 pixels on the left and by 15 pixels on the right, so the width of the rectangle shrinks by 30 each time through the loop. The height also shrinks by 30 pixels each time through the loop.
It is not hard to code this algorithm into Java and use it to define the drawFrame() method of the applet. I've assumed that the applet has a height of 160 pixels and a width of 300 pixels. The size is actually set in the source code of the Web page where the applet appears. In order for an applet to appear on a page, the source code for the page must include a command that specifies which applet to run and how big it should be. (We'll see how to do that later; see Exercise 3.6 and Section 6.2.) It's not a great idea to assume that we know how big the applet is going to be, as I do here; I'll address that issue before the end of this section. But for now, here is the source code for the applet:
import java.awt.*;

public class StaticRects extends AnimationBase {
   
     public void drawFrame(Graphics g) {
         
         // Draw set of nested black rectangles on a red background.
         // Each nested rectangle is separated by 15 pixels on all sides
         // from the rectangle that encloses it.  The applet is
         // assumed to be 300 pixels wide and 160 pixels high.
         
      int inset;    // Gap between borders of applet and one of the rectangles.
                    
      int rectWidth, rectHeight;   // The size of one of the rectangles.
                    
      g.setColor(Color.red);
      g.fillRect(0,0,300,160);  // Fill the entire applet with red.
      
      g.setColor(Color.black);  // Draw the rectangles in black.
                                       
      inset = 0;
      
      rectWidth = 299;    // Set size of the first rect to size of applet
      rectHeight = 159;
      
      while (rectWidth >= 0 && rectHeight >= 0) {
         g.drawRect(inset, inset, rectWidth, rectHeight);
         inset += 15;       // rects are 15 pixels apart
         rectWidth -= 30;   // width decreases by 15 pixels on left and 15 on right
         rectHeight -= 30;  // height decreases by 15 pixels on top and 15 on bottom
      }
      
   }  // end paint()

}  // end class StaticRects
(You might wonder why the initial rectWidth is set to 299, instead of to 300, since the width of the applet is 300 pixels. It's because rectangles are drawn as if with a pen whose nib hangs below and to the right of the point where the pen is placed. If you run the pen exactly along the right edge of the applet, the line it draws is actually outside the applet and therefore is not seen. So instead, we run the pen along a line one pixel to the left of the edge of the applet. The same reasoning applies to rectHeight. Careful graphics programming demands attention to details like these.)

When you write an animation applet, you get to build on AnimationBase which in turn builds on the work of the people who wrote the Applet class. The AnimationBase class provides a framework on which you can hang your own work. Any programmer can create additional frameworks that can be used by other programmers as a basis for writing specific types of applets or stand-alone programs. This makes it possible for other programmers to build on their work even without understanding in detail what goes on "inside" the code that they wrote. This type of thing is the key to building complex systems!
Let's continue our example by animating the rectangles in our applet. The animated version is shown at the bottom of this page.
In the animation, rectangles shrink continually towards the center of the applet, while new rectangles appear at the edge. The perpetual motion is, of course, an illusion. If you think about it, you'll see that the animation loops through the same set of images over and over. In each image, there is a gap between the borders of the applet and the outermost rectangle. This gap gets wider and wider until a new rectangle appears at the border. Only it's not a new rectangle. You are seeing a picture that is identical to the first picture that was drawn. What has really happened is that the animation has started over again with the first image in the sequence.
In order to create motion in the animation, drawFrame() will have to draw a different picture each time it is called. How can it do that? The picture that should be drawn will depend on the frame number, that is, how many frames have been drawn so far. To find out the current frame number, we can use a function that is built into the AnimationBase class. This class provides the function named getFrameNumber() that you can call to find out the current frame number. This function returns the current frame number as an integer value. If the value returned is 0, you are supposed to draw the first frame; if the value is 1, you are supposed to draw the second frame, and so on. Depending on the frame number, the drawFrame() method will draw different pictures.
In the animation that we are writing, the thing that differs from one frame to another is the distance between the edges of the applet and the outermost rectangle. Since the rectangles are 15 pixels apart, this distance increases from 0 to 14 and then jumps back to 0 when a "new" rectangle appears. The appropriate value can be computed very simply from the frame number, with the statement "inset = getFrameNumber() % 15;". The value of the expression getFrameNumber() % 15 is always between 0 and 14. When the frame number reaches 15 or any multiple of 15, the value ofgetFrameNumber() % 15 jumps back to 0.
Drawing one frame in the sample animated applet is very similar to drawing the single image of the original StaticRects applet. We only have to make a few changes to the drawFrame() method. I've chosen to make one additional improvement: The StaticRects applet assumes that the applet is exactly 300 by 160 pixels. The new version, MovingRects, will work for any applet size. To implement this, thedrawFrame() routine has to know how big the applet is. There are two functions that can be called to get this information. The function getWidth() returns an integer value representing the width of the applet, and the function getHeight() returns the height. These functions are inherited from the Applet class. The width and height, together with the frame number, are used to compute the size of the first rectangle that is drawn. Here is the complete source code:
import java.awt.*;

public class MovingRects extends AnimationBase {


  public void init() {
        // The init() method is called when the applet is first
        // created and can be used to initialize the applet.
        // Here, it is used to change the number of milliseconds
        // per frame from the default 100 to 30.  The faster
        // animation looks better.
     setMillisecondsPerFrame(30);
  }


  public void drawFrame(Graphics g) {

         // Draw one frame in the animation by filling in the background
         // with a solid red and then drawing a set of nested black
         // rectangles.  The frame number tells how much the first 
         // rectangle is to be inset from the borders of the applet.
         
      int width;    // Width of the applet, in pixels.
      int height;   // Height of the applet, in pixels.
      
      int inset;    // Gap between borders of applet and a rectangle.
                    //    The inset for the outermost rectangle goes from 0 to
                    //    14 then back to 0, and so on, as the frameNumber varies.
                    
      int rectWidth, rectHeight;   // the size of one of the rectangles
                    
      width = getWidth();              // find out the size of the drawing area
      height = getHeight();

      g.setColor(Color.red);           // fill the frame with red
      g.fillRect(0,0,width,height);
      
      g.setColor(Color.black);         // switch color to black

      inset = getFrameNumber() % 15;   // get the inset for the outermost rect
                                       
      rectWidth = width - 2*inset - 1;    // set size of the outermost rect
      rectHeight = height - 2*inset - 1;
      
      while (rectWidth >= 0 && rectHeight >= 0) {
         g.drawRect(inset,inset,rectWidth,rectHeight);
         inset += 15;       // rects are 15 pixels apart
         rectWidth -= 30;   // width decreases by 15 pixels on left and 15 on right
         rectHeight -= 30;  // height decreases by 15 pixels on top and 15 on bottom
      }
      
   }  // end drawFrame()

}  // end class MovingRects
The main point here is that by building on an existing framework,


Introduction to Exceptions and try..catch


IN ADDITION TO THE CONTROL structures that determine the normal flow of control in a program, Java has a way to deal with "exceptional" cases that throw the flow of control off its normal track. When an error occurs during the execution of a program, the default behavior is to terminate the program and to print an error message. However, Java makes it possible to "catch" such errors and program a response different from simply letting the program crash. This is done with the try..catch statement. In this section, we will take a preliminary, incomplete look at using try..catch to handle errors. Error handling is a complex topic, which we will return to in Chapter 8.

3.7.1  Exceptions

The term exception is used to refer to the type of error that one might want to handle with a try..catch. An exception is an exception to the normal flow of control in the program. The term is used in preference to "error" because in some cases, an exception might not be considered to be an error at all. You can sometimes think of an exception as just another way to organize a program.
Exceptions in Java are represented as objects of type Exception. Actual exceptions are defined by subclasses of Exception. Different subclasses represent different types of exceptions. We will look at only two types of exception in this section: NumberFormatException and IllegalArgumentException.
NumberFormatException can occur when an attempt is made to convert a string into a number. Such conversions are done by the functions Integer.parseInt and Double.parseDouble. (SeeSubsection 2.5.7.) Consider the function call Integer.parseInt(str) where str is a variable of type String. If the value of str is the string "42", then the function call will correctly convert the string into theint 42. However, if the value of str is, say, "fred", the function call will fail because "fred" is not a legal string representation of an int value. In this case, an exception of type NumberFormatExceptionoccurs. If nothing is done to handle the exception, the program will crash.
An IllegalArgumentException can occur when an illegal value is passed as a parameter to a subroutine. For example, if a subroutine requires that a parameter be greater than or equal to zero, anIllegalArgumentException might occur when a negative value is passed to the subroutine. How to respond to the illegal value is up to the person who wrote the subroutine, so we can't simply say that every illegal parameter value will result in an IllegalArgumentException. However, it is a common response.
One case where an IllegalArgumentException can occur is in the valueOf function of an enumerated type. Recall from Subsection 2.3.3 that this function tries to convert a string into one of the values of the enumerated type. If the string that is passed as a parameter to valueOf is not the name of one of the enumerated type's values, then an IllegalArgumentException occurs. For example, given the enumerated type
enum Toss { HEADS, TAILS }
Toss.valueOf("HEADS") correctly returns the value Toss.HEADS, while Toss.valueOf("FEET") results in an IllegalArgumentException.

3.7.2  try..catch

When an exception occurs, we say that the exception is "thrown". For example, we say that Integer.parseInt(str) throws an exception of type NumberFormatException when the value of str is illegal. When an exception is thrown, it is possible to "catch" the exception and prevent it from crashing the program. This is done with a try..catch statement. In somewhat simplified form, the syntax for a try..catchis:
try {
   statements-1
}
catch ( exception-class-name  variable-name ) {
   statements-2
}
The exception-class-name could be NumberFormatExceptionIllegalArgumentException, or some other exception class. When the computer executes this statement, it executes the statements in the trypart. If no error occurs during the execution of statements-1, then the computer just skips over the catch part and proceeds with the rest of the program. However, if an exception of type exception-class-name occurs during the execution of statements-1, the computer immediately jumps to the catch part and executes statements-2, skipping any remaining statements in statements-1. During the execution ofstatements-2, the variable-name represents the exception object, so that you can, for example, print it out. At the end of the catch part, the computer proceeds with the rest of the program; the exception has been caught and handled and does not crash the program. Note that only one type of exception is caught; if some other type of exception occurs during the execution of statements-1, it will crash the program as usual.
By the way, note that the braces, { and }, are part of the syntax of the try..catch statement. They are required even if there is only one statement between the braces. This is different from the other statements we have seen, where the braces around a single statement are optional.
As an example, suppose that str is a variable of type String whose value might or might not represent a legal real number. Then we could say:
try {
   double x;
   x = Double.parseDouble(str);
   System.out.println( "The number is " + x );
}
catch ( NumberFormatException e ) {
   System.out.println( "Not a legal number." );
}
If an error is thrown by the call to Double.parseDouble(str), then the output statement in the try part is skipped, and the statement in the catch part is executed.
It's not always a good idea to catch exceptions and continue with the program. Often that can just lead to an even bigger mess later on, and it might be better just to let the exception crash the program at the point where it occurs. However, sometimes it's possible to recover from an error. For example, suppose that we have the enumerated type
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
and we want the user to input a value belonging to this type. TextIO does not know about this type, so we can only read the user's response as a string. The function Day.valueOf can be used to convert the user's response to a value of type Day. This will throw an exception of type IllegalArgumentException if the user's response is not the name of one of the values of type Day, but we can recover from the error easily enough by asking the user to enter another response. Here is a code segment that does this. (Converting the user's response to upper case will allow responses such as "Monday" or "monday" in addition to "MONDAY".)
Day  weekday;  // User's response as a value of type Day.
while ( true ) {
   String response;  // User's response as a String.
   System.out.print("Please enter a day of the week: ");
   response = TextIO.getln();
   response = response.toUpperCase();
   try {
      weekday = Day.valueOf(response);
      break;
   }
   catch ( IllegalArgumentException e ) {
      System.out.println( response + " is not the name of a day of the week." );
   }
}
// At this point, a legal value has definitely been assigned to weekday.
The break statement will be reached only if the user's response is acceptable, and so the loop will end only when a legal value has been assigned to weekday.

3.7.3  Exceptions in TextIO

When TextIO reads a numeric value from the user, it makes sure that the user's response is legal, using a technique similar to the while loop and try..catch in the previous example. However, TextIO can read data from other sources besides the user. (See Subsection 2.4.5.) When it is reading from a file, there is no reasonable way for TextIO to recover from an illegal value in the input, so it responds by throwing an exception. To keep things simple, TextIO only throws exceptions of type IllegalArgumentException, no matter what type of error it encounters. For example, an exception will occur if an attempt is made to read from a file after all the data in the file has already been read. In TextIO, the exception is of type IllegalArgumentException. If you have a better response to file errors than to let the program crash, you can use a try..catch to catch exceptions of type IllegalArgumentException.
For example, suppose that a file contains nothing but real numbers, and we want a program that will read the numbers and find their sum and their average. Since it is unknown how many numbers are in the file, there is the question of when to stop reading. One approach is simply to try to keep reading indefinitely. When the end of the file is reached, an exception occurs. This exception is not really an error -- it's just a way of detecting the end of the data, so we can catch the exception and finish up the program. We can read the data in a while (true) loop and break out of the loop when an exception occurs. This is an example of the somewhat unusual technique of using an exception as part of the expected flow of control in a program.
To read from the file, we need to know the file's name. To make the program more general, we can let the user enter the file name, instead of hard-coding a fixed file name in the program. However, it is possible that the user will enter the name of a file that does not exist. When we use TextIO.readfile to open a file that does not exist, an exception of type IllegalArgumentException occurs. We can catch this exception and ask the user to enter a different file name. Here is a complete program that uses all these ideas:
/**
 * This program reads numbers from a file.  It computes the sum and 
 * the average of the numbers that it reads.  The file should contain 
 * nothing but numbers of type double; if this is not the case, the 
 * output will be the sum and average of however many numbers were 
 * successfully read from the file.  The name of the file will be
 * input by the user.
 */

public class ReadNumbersFromFile {
   
   public static void main(String[] args) {
            
      while (true) {
         String fileName;  // The name of the file, to be input by the user.
         TextIO.put("Enter the name of the file: ");
         fileName = TextIO.getln();
         try {
            TextIO.readFile( fileName );  // Try to open the file for input.
            break;  // If that succeeds, break out of the loop.
         }
         catch ( IllegalArgumentException e ) {
            TextIO.putln("Can't read from the file \"" + fileName + "\".");
            TextIO.putln("Please try again.\n");
         }
      }
      
      // At this point, TextIO is reading from the file.
      
      double number;  // A number read from the data file.
      double sum;     // The sum of all the numbers read so far.
      int count;      // The number of numbers that were read.
      
      sum = 0;
      count = 0;
      
      try {
         while (true) { // Loop ends when an exception occurs.
             number = TextIO.getDouble();
             count++;  // This is skipped when the exception occurs
             sum += number;
         }
      }
      catch ( IllegalArgumentException e ) {
         // We expect this to occur when the end-of-file is encountered.
         // We don't consider this to be an error, so there is nothing to do
         // in this catch clause.  Just proceed with the rest of the program.
      }
      
      // At this point, we've read the entire file.
      
      TextIO.putln();
      TextIO.putln("Number of data values read: " + count);
      TextIO.putln("The sum of the data values: " + sum);
      if ( count == 0 )
         TextIO.putln("Can't compute an average of 0 values.");
      else
         TextIO.putln("The average of the values:  " + (sum/count));
      
   }

}



The switch Statement


THE SECOND BRANCHING STATEMENT in Java is the switch statement, which is introduced in this section. The switch statement is used far less often than the if statement, but it is sometimes useful for expressing a certain type of multi-way branch.

3.6.1  The Basic switch Statement

A switch statement allows you to test the value of an expression and, depending on that value, to jump directly to some location within the switch statement. Only expressions of certain types can be used. The value of the expression can be one of the primitive integer types intshort, or byte. It can be the primitive char type. Or, as we will see later in this section, it can be an enumerated type. In Java 7, Strings are also allowed. In particular, the expression cannot be a real number, and prior to Java 7, it cannot be a String. The positions that you can jump to are marked with case labels that take the form: "case constant:". This marks the position the computer jumps to when the expression evaluates to the given constant. As the final case in a switch statement you can, optionally, use the label "default:", which provides a default jump point that is used when the value of the expression is not listed in any case label.
switch statement, as it is most often used, has the form:
switch (expression) {
   case constant-1:
      statements-1
      break;
   case constant-2:
      statements-2
      break;
      .
      .   // (more cases)
      .
   case constant-N:
      statements-N
      break;
   default:  // optional default case
      statements-(N+1)
} // end of switch statement
The break statements are technically optional. The effect of a break is to make the computer jump to the end of the switch statement. If you leave out the break statement, the computer will just forge ahead after completing one case and will execute the statements associated with the next case label. This is rarely what you want, but it is legal. (I will note here -- although you won't understand it until you get to the next chapter -- that inside a subroutine, the break statement is sometimes replaced by a return statement.)
Note that you can leave out one of the groups of statements entirely (including the break). You then have two case labels in a row, containing two different constants. This just means that the computer will jump to the same place and perform the same action for each of the two constants.
Here is an example of a switch statement. This is not a useful example, but it should be easy for you to follow. Note, by the way, that the constants in the case labels don't have to be in any particular order, as long as they are all different:
switch ( N ) {   // (Assume N is an integer variable.)
   case 1:
      System.out.println("The number is 1.");
      break;
   case 2:
   case 4:
   case 8:
      System.out.println("The number is 2, 4, or 8.");
      System.out.println("(That's a power of 2!)");
      break;
   case 3:
   case 6:
   case 9:
      System.out.println("The number is 3, 6, or 9.");
      System.out.println("(That's a multiple of 3!)");
      break;
   case 5:
      System.out.println("The number is 5.");
      break;
   default:
      System.out.println("The number is 7 or is outside the range 1 to 9.");
}
The switch statement is pretty primitive as control structures go, and it's easy to make mistakes when you use it. Java takes all its control structures directly from the older programming languages C and C++. The switch statement is certainly one place where the designers of Java should have introduced some improvements.

3.6.2  Menus and switch Statements

One application of switch statements is in processing menus. A menu is a list of options. The user selects one of the options. The computer has to respond to each possible choice in a different way. If the options are numbered 1, 2, ..., then the number of the chosen option can be used in a switch statement to select the proper response.
In a TextIO-based program, the menu can be presented as a numbered list of options, and the user can choose an option by typing in its number. Here is an example that could be used in a variation of theLengthConverter example from the previous section:
int optionNumber;   // Option number from menu, selected by user.
double measurement; // A numerical measurement, input by the user.
                    //    The unit of measurement depends on which
                    //    option the user has selected.
double inches;      // The same measurement, converted into inches.

/* Display menu and get user's selected option number. */

TextIO.putln("What unit of measurement does your input use?");
TextIO.putln();
TextIO.putln("         1.  inches");
TextIO.putln("         2.  feet");
TextIO.putln("         3.  yards");
TextIO.putln("         4.  miles");
TextIO.putln();
TextIO.putln("Enter the number of your choice: ");
optionNumber = TextIO.getlnInt();

/* Read user's measurement and convert to inches. */

switch ( optionNumber ) {
   case 1:
       TextIO.putln("Enter the number of inches: ");
       measurement = TextIO.getlnDouble();
       inches = measurement;
       break;          
   case 2:
       TextIO.putln("Enter the number of feet: ");
       measurement = TextIO.getlnDouble();
       inches = measurement * 12;
       break;          
   case 3:
       TextIO.putln("Enter the number of yards: ");
       measurement = TextIO.getlnDouble();
       inches = measurement * 36;
       break;          
   case 4:
       TextIO.putln("Enter the number of miles: ");
       measurement = TextIO.getlnDouble();
       inches = measurement * 12 * 5280;
       break;
   default:
       TextIO.putln("Error!  Illegal option number!  I quit!");
       System.exit(1);          
} // end switch

/* Now go on to convert inches to feet, yards, and miles... */
In Java 7, this example might be rewritten using a String in the switch statement:
String units;       // Unit of measurement, entered by user.
double measurement; // A numerical measurement, input by the user.
double inches;      // The same measurement, converted into inches.

/* Read the user's unit of measurement. */

TextIO.putln("What unit of measurement does your input use?");
TextIO.put("inches, feet, yards, or miles ?");
units = TextIO.getln().toLowerCase();

/* Read user's measurement and convert to inches. */

TextIO.put("Enter the number of " + units + ":  ");
measurement = TextIO.getlnDouble();

switch ( units ) {  // Requires Java 7 or higher!
   case "inches":
       inches = measurement;
       break;          
   case "feet":
       inches = measurement * 12;
       break;          
   case "yards":
       inches = measurement * 36;
       break;          
   case "miles":
       inches = measurement * 12 * 5280;
       break;
   default:
       TextIO.putln("Wait a minute!  Illegal unit of measure!  I quit!");
       System.exit(1);          
} // end switch

3.6.3  Enums in switch Statements

The type of the expression in a switch can be an enumerated type. In that case, the constants in the case labels must be values from the enumerated type. For example, if the type of the expression is the enumerated type Season defined by
enum Season { SPRING, SUMMER, FALL, WINTER }
then the constants in the case label must be chosen from among the values Season.SPRINGSeason.SUMMERSeason.FALL, or Season.WINTER. However, there is another quirk in the syntax: when an enum constant is used in a case label, only the simple name, such as "SPRING" can be used, not the full name "Season.SPRING". Of course, the computer already knows that the value in the case label must belong to the enumerated type, since it can tell that from the type of expression used, so there is really no need to specify the type name in the constant. As an example, suppose that currentSeason is a variable of typeSeason. Then we could have the switch statement:
switch ( currentSeason ) {
   case WINTER:    // ( NOT Season.WINTER ! )
      System.out.println("December, January, February");
      break;
   case SPRING:
      System.out.println("March, April, May");
      break;
   case SUMMER:
      System.out.println("June, July, August");
      break;
   case FALL:
      System.out.println("September, October, November");
      break;
}

3.6.4  Definite Assignment

As a somewhat more realistic example, the following switch statement makes a random choice among three possible alternatives. Recall that the value of the expression (int)(3*Math.random()) is one of the integers 0, 1, or 2, selected at random with equal probability, so the switch statement below will assign one of the values "Rock""Scissors""Paper" to computerMove, with probability 1/3 for each case. Although the switch statement in this example is correct, this code segment as a whole illustrates a subtle syntax error that sometimes comes up:
String computerMove;
switch ( (int)(3*Math.random()) ) {
   case 0:
      computerMove = "Rock";
      break;
   case 1:
      computerMove = "Scissors";
      break;
   case 2:
      computerMove = "Paper";
      break;
}
System.out.println("Computer's move is " + computerMove);   // ERROR!
You probably haven't spotted the error, since it's not an error from a human point of view. The computer reports the last line to be an error, because the variable computerMove might not have been assigned a value. In Java, it is only legal to use the value of a variable if a value has already been definitely assigned to that variable. This means that the computer must be able to prove, just from looking at the code when the program is compiled, that the variable must have been assigned a value. Unfortunately, the computer only has a few simple rules that it can apply to make the determination. In this case, it sees a switchstatement in which the type of expression is int and in which the cases that are covered are 0, 1, and 2. For other values of the expression, computerMove is never assigned a value. So, the computer thinkscomputerMove might still be undefined after the switch statement. Now, in fact, this isn't true: 0, 1, and 2 are actually the only possible values of the expression (int)(3*Math.random()), but the computer isn't smart enough to figure that out. The easiest way to fix the problem is to replace the case label case 2 with default. The computer can then see that a value is assigned to computerMove in all cases.
More generally, we say that a value has been definitely assigned to a variable at a given point in a program if every execution path leading from the declaration of the variable to that point in the code includes an assignment to the variable. This rule takes into account loops and if statements as well as switch statements. For example, the following two if statements both do the same thing as the switch statement given above, but only the one on the right definitely assigns a value to computerMove:
String computerMove;                     String computerMove;
int rand;                                int rand;
rand = (int)(3*Math.random());           rand = (int)(3*Math.random());
if ( rand == 0 )                         if ( rand == 0 )
   computerMove = "Rock";                   computerMove = "Rock";
else if ( rand == 1 )                    else if ( rand == 1 )
   computerMove = "Scissors";               computerMove = "Scissors";
else if ( rand == 2 )                    else
   computerMove = "Paper";                  computerMove = "Paper";
In the code on the left, the test "if ( rand == 2 )" in the final else clause is unnecessary because if rand is not 0 or 1, the only remaining possibility is that rand == 2. The computer, however, can't figure that out.



The if Statement


THE FIRST OF THE TWO BRANCHING STATEMENTS in Java is the if statement, which you have already seen in Section 3.1. It takes the form
if (boolean-expression)
     statement-1
else
     statement-2
As usual, the statements inside an if statement can be blocks. The if statement represents a two-way branch. The else part of an if statement -- consisting of the word "else" and the statement that follows it -- can be omitted.

3.5.1  The Dangling else Problem

Now, an if statement is, in particular, a statement. This means that either statement-1 or statement-2 in the above if statement can itself be an if statement. A problem arises, however, if statement-1 is anif statement that has no else part. This special case is effectively forbidden by the syntax of Java. Suppose, for example, that you type
if ( x > 0 )
    if (y > 0)
       System.out.println("First case");
else
    System.out.println("Second case");
Now, remember that the way you've indented this doesn't mean anything at all to the computer. You might think that the else part is the second half of your "if (x > 0)" statement, but the rule that the computer follows attaches the else to "if (y > 0)", which is closer. That is, the computer reads your statement as if it were formatted:
if ( x > 0 )
    if (y > 0)
       System.out.println("First case");
    else
        System.out.println("Second case");
You can force the computer to use the other interpretation by enclosing the nested if in a block:
if ( x > 0 ) {
    if (y > 0)
       System.out.println("First case");
}
else
    System.out.println("Second case");
These two if statements have different meanings: In the case when x <= 0, the first statement doesn't print anything, but the second statement prints "Second case".

3.5.2  The if...else if Construction

Much more interesting than this technicality is the case where statement-2, the else part of the if statement, is itself an if statement. The statement would look like this (perhaps without the final else part):
if (boolean-expression-1)
     statement-1
else
     if (boolean-expression-2)
         statement-2
     else
         statement-3
However, since the computer doesn't care how a program is laid out on the page, this is almost always written in the format:
if (boolean-expression-1)
     statement-1
else if (boolean-expression-2)
     statement-2
else
     statement-3
You should think of this as a single statement representing a three-way branch. When the computer executes this, one and only one of the three statements -- statement-1statement-2, or statement-3 -- will be executed. The computer starts by evaluating boolean-expression-1. If it is true, the computer executes statement-1 and then jumps all the way to the end of the outer if statement, skipping the other twostatements. If boolean-expression-1 is false, the computer skips statement-1 and executes the second, nested if statement. To do this, it tests the value of boolean-expression-2 and uses it to decide between statement-2 and statement-3.
Here is an example that will print out one of three different messages, depending on the value of a variable named temperature:
if (temperature < 50)
   System.out.println("It's cold.");
else if (temperature < 80)
   System.out.println("It's nice.");
else
   System.out.println("It's hot.");
If temperature is, say, 42, the first test is true. The computer prints out the message "It's cold", and skips the rest -- without even evaluating the second condition. For a temperature of 75, the first test isfalse, so the computer goes on to the second test. This test is true, so the computer prints "It's nice" and skips the rest. If the temperature is 173, both of the tests evaluate to false, so the computer says "It's hot" (unless its circuits have been fried by the heat, that is).
You can go on stringing together "else-if's" to make multi-way branches with any number of cases:
if (boolean-expression-1)
     statement-1
else if (boolean-expression-2)
     statement-2
else if (boolean-expression-3)
     statement-3
  .
  . // (more cases)
  .
else if (boolean-expression-N)
     statement-N
else
     statement-(N+1)
The computer evaluates boolean expressions one after the other until it comes to one that is true. It executes the associated statement and skips the rest. If none of the boolean expressions evaluate to true, then the statement in the else part is executed. This statement is called a multi-way branch because only one of the statements will be executed. The final else part can be omitted. In that case, if all the boolean expressions are false, none of the statements are executed. Of course, each of the statements can be a block, consisting of a number of statements enclosed between { and }. (Admittedly, there is lot of syntax here; as you study and practice, you'll become comfortable with it.)

3.5.3  If Statement Examples

As an example of using if statements, lets suppose that xy, and z are variables of type int, and that each variable has already been assigned a value. Consider the problem of printing out the values of the three variables in increasing order. For examples, if the values are 42, 17, and 20, then the output should be in the order 17, 20, 42.
One way to approach this is to ask, where does x belong in the list? It comes first if it's less than both y and z. It comes last if it's greater than both y and z. Otherwise, it comes in the middle. We can express this with a 3-way if statement, but we still have to worry about the order in which y and z should be printed. In pseudocode,
if (x < y && x < z) {
    output x, followed by y and z in their correct order
}
else if (x > y && x > z) {
    output y and z in their correct order, followed by x
}
else {
    output x in between y and z in their correct order
}
Determining the relative order of y and z requires another if statement, so this becomes
if (x < y && x < z) {        // x comes first
    if (y < z)
       System.out.println( x + " " + y + " " + z );
    else
       System.out.println( x + " " + z + " " + y );
}
else if (x > y && x > z) {   // x comes last
    if (y < z)
       System.out.println( y + " " + z + " " + x );
    else
       System.out.println( z + " " + y + " " + x );
}
else {                       // x in the middle
    if (y < z)
       System.out.println( y + " " + x + " " + z);
    else
       System.out.println( z + " " + x + " " + y);
}
You might check that this code will work correctly even if some of the values are the same. If the values of two variables are the same, it doesn't matter which order you print them in.
Note, by the way, that even though you can say in English "if x is less than y and z," you can't say in Java "if (x < y && z)". The && operator can only be used between boolean values, so you have to make separate tests, x<y and x<z, and then combine the two tests with &&.
There is an alternative approach to this problem that begins by asking, "which order should x and y be printed in?" Once that's known, you only have to decide where to stick in z. This line of thought leads to different Java code:
if ( x < y ) {  // x comes before y
   if ( z < x )   // z comes first
      System.out.println( z + " " + x + " " + y);
   else if ( z > y )   // z comes last
      System.out.println( x + " " + y + " " + z);
   else   // z is in the middle
      System.out.println( x + " " + z + " " + y);
}
else {          // y comes before x
   if ( z < y )   // z comes first
      System.out.println( z + " " + y + " " + x);
   else if ( z > x )  // z comes last
      System.out.println( y + " " + x + " " + z);
   else  // z is in the middle
      System.out.println( y + " " + z + " " + x);
}
Once again, we see how the same problem can be solved in many different ways. The two approaches to this problem have not exhausted all the possibilities. For example, you might start by testing whether x is greater than y. If so, you could swap their values. Once you've done that, you know that x should be printed before y.

Finally, let's write a complete program that uses an if statement in an interesting way. I want a program that will convert measurements of length from one unit of measurement to another, such as miles to yards or inches to feet. So far, the problem is extremely under-specified. Let's say that the program will only deal with measurements in inches, feet, yards, and miles. It would be easy to extend it later to deal with other units. The user will type in a measurement in one of these units, such as "17 feet" or "2.73 miles". The output will show the length in terms of each of the four units of measure. (This is easier than asking the user which units to use in the output.) An outline of the process is
Read the user's input measurement and units of measure
Express the measurement in inches, feet, yards, and miles
Display the four results
The program can read both parts of the user's input from the same line by using TextIO.getDouble() to read the numerical measurement and TextIO.getlnWord() to read the unit of measure. The conversion into different units of measure can be simplified by first converting the user's input into inches. From there, the number of inches can easily be converted into feet, yards, and miles. Before converting into inches, we have to test the input to determine which unit of measure the user has specified:
Let measurement = TextIO.getDouble()
Let units = TextIO.getlnWord()
if the units are inches
   Let inches = measurement
else if the units are feet
   Let inches = measurement * 12         // 12 inches per foot
else if the units are yards
   Let inches = measurement * 36         // 36 inches per yard
else if the units are miles
   Let inches = measurement * 12 * 5280  // 5280 feet per mile
else
   The units are illegal!
   Print an error message and stop processing
Let feet = inches / 12.0
Let yards = inches / 36.0
Let miles = inches / (12.0 * 5280.0)
Display the results
Since units is a String, we can use units.equals("inches") to check whether the specified unit of measure is "inches". However, it would be nice to allow the units to be specified as "inch" or abbreviated to "in". To allow these three possibilities, we can check if (units.equals("inches") || units.equals("inch") || units.equals("in")). It would also be nice to allow upper case letters, as in "Inches" or "IN". We can do this by converting units to lower case before testing it or by substituting the function units.equalsIgnoreCase for units.equals.
In my final program, I decided to make things more interesting by allowing the user to repeat the process of entering a measurement and seeing the results of the conversion for each measurement. The program will end only when the user inputs 0. To do this, I just have to wrap the above algorithm inside a while loop, and make sure that the loop ends when the user inputs a 0. Here's the complete program, followed by an applet that simulates it:
/**
 * This program will convert measurements expressed in inches,
 * feet, yards, or miles into each of the possible units of
 * measure.  The measurement is input by the user, followed by
 * the unit of measure.  For example:  "17 feet", "1 inch", or
 * "2.73 mi".  Abbreviations in, ft, yd, and mi are accepted.
 * The program will continue to read and convert measurements
 * until the user enters an input of 0.
 */
 
 public class LengthConverter {
 
    public static void main(String[] args) {
       
       double measurement;  // Numerical measurement, input by user.
       String units;        // The unit of measure for the input, also
                            //    specified by the user.
       
       double inches, feet, yards, miles;  // Measurement expressed in
                                           //   each possible unit of
                                           //   measure.
       
       TextIO.putln("Enter measurements in inches, feet, yards, or miles.");
       TextIO.putln("For example:  1 inch    17 feet    2.73 miles");
       TextIO.putln("You can use abbreviations:   in   ft  yd   mi");
       TextIO.putln("I will convert your input into the other units");
       TextIO.putln("of measure.");
       TextIO.putln();
       
       while (true) {
          
          /* Get the user's input, and convert units to lower case. */
          
          TextIO.put("Enter your measurement, or 0 to end:  ");
          measurement = TextIO.getDouble();
          if (measurement == 0)
             break;  // Terminate the while loop.
          units = TextIO.getlnWord();            
          units = units.toLowerCase();
          
          /* Convert the input measurement to inches. */
          
          if (units.equals("inch") || units.equals("inches") 
                                          || units.equals("in")) {
              inches = measurement;
          }
          else if (units.equals("foot") || units.equals("feet") 
                                          || units.equals("ft")) {
              inches = measurement * 12;
          }
          else if (units.equals("yard") || units.equals("yards") 
                                           || units.equals("yd")) {
              inches = measurement * 36;
          }
          else if (units.equals("mile") || units.equals("miles") 
                                             || units.equals("mi")) {
              inches = measurement * 12 * 5280;
          }
          else {
              TextIO.putln("Sorry, but I don't understand \"" 
                                                   + units + "\".");
              continue;  // back to start of while loop
          }
          
          /* Convert measurement in inches to feet, yards, and miles. */
          
          feet = inches / 12;
          yards = inches / 36;
          miles = inches / (12*5280);
          
          /* Output measurement in terms of each unit of measure. */
          
          TextIO.putln();
          TextIO.putln("That's equivalent to:");
          TextIO.putf("%12.5g", inches);
          TextIO.putln(" inches");
          TextIO.putf("%12.5g", feet);
          TextIO.putln(" feet");
          TextIO.putf("%12.5g", yards);
          TextIO.putln(" yards");
          TextIO.putf("%12.5g", miles);
          TextIO.putln(" miles");
          TextIO.putln();
       
       } // end while
       
       TextIO.putln();
       TextIO.putln("OK!  Bye for now.");
       
    } // end main()
    
 } // end class LengthConverter
(Note that this program uses formatted output with the "g" format specifier. In this program, we have no control over how large or how small the numbers might be. It could easily make sense for the user to enter very large or very small measurements. The "g" format will print a real number in exponential form if it is very large or very small, and in the usual decimal form otherwise. Remember that in the format specification%12.5g, the 5 is the total number of significant digits that are to be printed, so we will always get the same number of significant digits in the output, no matter what the size of the number. If we had used an "f" format specifier such as %12.5f, the output would be in decimal form with 5 digits after the decimal point. This would print the number 0.000000000745482 as 0.00000, with no significant digits at all! With the "g" format specifier, the output would be 7.4549e-10.)

3.5.4  The Empty Statement

As a final note in this section, I will mention one more type of statement in Java: the empty statement. This is a statement that consists simply of a semicolon and which tells the computer to do nothing. The existence of the empty statement makes the following legal, even though you would not ordinarily see a semicolon after a } :
if (x < 0) {
    x = -x;
};
The semicolon is legal after the }, but the computer considers it to be an empty statement, not part of the if statement. Occasionally, you might find yourself using the empty statement when what you mean is, in fact, "do nothing." For example, the rather contrived if statement
if ( done )
   ;  // Empty statement
else
   System.out.println( "Not done yet. );
does nothing when the boolean variable done is true, and prints out "Not done yet" when it is false. You can't just leave out the semicolon in this example, since Java syntax requires an actual statement between the if and the else. I prefer, though, to use an empty block, consisting of { and } with nothing between, for such cases.
Occasionally, stray empty statements can cause annoying, hard-to-find errors in a program. For example, the following program segment prints out "Hello" just once, not ten times:
for (int i = 0; i < 10; i++);
    System.out.println("Hello");
Why? Because the ";" at the end of the first line is a statement, and it is this statement that is executed ten times. The System.out.println statement is not really inside the for statement at all, so it is executed just once, after the for loop has completed.



The for Statement


WE TURN IN THIS SECTION to another type of loop, the for statement. Any for loop is equivalent to some while loop, so the language doesn't get any additional power by having for statements. But for a certain type of problem, a for loop can be easier to construct and easier to read than the corresponding while loop. It's quite possible that in real programs, for loops actually outnumber while loops.

3.4.1  For Loops

The for statement makes a common type of while loop easier to write. Many while loops have the general form:
initialization
while ( continuation-condition ) {
    statements
    update
}
For example, consider this example, copied from an example in Section 3.2:
years = 0;  // initialize the variable years
while ( years < 5 ) {   // condition for continuing loop

    interest = principal * rate;    //
    principal += interest;          // do three statements
    System.out.println(principal);  //
    
    years++;   // update the value of the variable, years
}
This loop can be written as the following equivalent for statement:
for ( years = 0;  years < 5;  years++ ) {
   interest = principal * rate;
   principal += interest;
   System.out.println(principal);
}
The initialization, continuation condition, and updating have all been combined in the first line of the for loop. This keeps everything involved in the "control" of the loop in one place, which helps make the loop easier to read and understand. The for loop is executed in exactly the same way as the original code: The initialization part is executed once, before the loop begins. The continuation condition is executed before each execution of the loop, and the loop ends when this condition is false. The update part is executed at the end of each execution of the loop, just before jumping back to check the condition.
The formal syntax of the for statement is as follows:
for ( initialization; continuation-condition; update )
     statement
or, using a block statement:
for ( initialization; continuation-condition; update ) {
     statements
}
The continuation-condition must be a boolean-valued expression. The initialization is usually a declaration or an assignment statement, but it can be any expression that would be allowed as a statement in a program. The update can be any expression statement, but is usually an increment, a decrement, or an assignment statement. Any of the three can be empty. If the continuation condition is empty, it is treated as if it were "true," so the loop will be repeated forever or until it ends for some other reason, such as a break statement. (Some people like to begin an infinite loop with "for (;;)" instead of "while (true)".)
Usually, the initialization part of a for statement assigns a value to some variable, and the update changes the value of that variable with an assignment statement or with an increment or decrement operation. The value of the variable is tested in the continuation condition, and the loop ends when this condition evaluates to false. A variable used in this way is called a loop control variable. In the for statement given above, the loop control variable is years.
Certainly, the most common type of for loop is the counting loop, where a loop control variable takes on all integer values between some minimum and some maximum value. A counting loop has the form
for ( variable = min;  variable <= max; variable++ ) {
     statements
}
where min and max are integer-valued expressions (usually constants). The variable takes on the values minmin+1, min+2, ..., max. The value of the loop control variable is often used in the body of the loop. The for loop at the beginning of this section is a counting loop in which the loop control variable, years, takes on the values 1, 2, 3, 4, 5. Here is an even simpler example, in which the numbers 1, 2, ..., 10 are displayed on standard output:
for ( N = 1 ;  N <= 10 ;  N++ )
   System.out.println( N );
For various reasons, Java programmers like to start counting at 0 instead of 1, and they tend to use a "<" in the condition, rather than a "<=". The following variation of the above loop prints out the ten numbers 0, 1, 2, ..., 9:
for ( N = 0 ;  N < 10 ;  N++ )
   System.out.println( N );
Using < instead of <= in the test, or vice versa, is a common source of off-by-one errors in programs. You should always stop and think, Do I want the final value to be processed or not?
It's easy to count down from 10 to 1 instead of counting up. Just start with 10, decrement the loop control variable instead of incrementing it, and continue as long as the variable is greater than or equal to one.
for ( N = 10 ;  N >= 1 ;  N-- )
   System.out.println( N );
Now, in fact, the official syntax of a for statement actually allows both the initialization part and the update part to consist of several expressions, separated by commas. So we can even count up from 1 to 10 and count down from 10 to 1 at the same time!
for ( i=1, j=10;  i <= 10;  i++, j-- ) {
   System.out.printf("%5d", i); // Output i in a 5-character wide column.
   System.out.printf("%5d", j); // Output j in a 5-character column 
   System.out.println();       //     and end the line.
}
As a final introductory example, let's say that we want to use a for loop that prints out just the even numbers between 2 and 20, that is: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20. There are several ways to do this. Just to show how even a very simple problem can be solved in many ways, here are four different solutions (three of which would get full credit):
 (1)   // There are 10 numbers to print.           
       // Use a for loop to count 1, 2,            
       // ..., 10.  The numbers we want            
       // to print are 2*1, 2*2, ... 2*10.         
   
       for (N = 1; N <= 10; N++) {              
          System.out.println( 2*N );                
       }
       
       
 (2)   // Use a for loop that counts
       // 2, 4, ..., 20 directly by
       // adding 2 to N each time through
       // the loop.
       
       for (N = 2; N <= 20; N = N + 2) {
          System.out.println( N );
       }
       
       
 (3)   // Count off all the numbers    
       // 2, 3, 4, ..., 19, 20, but                
       // only print out the numbers               
       // that are even.                           
    
       for (N = 2; N <= 20; N++) {               
          if ( N % 2 == 0 ) // is N even?           
             System.out.println( N );               
       } 
   
   
 (4)   // Irritate the professor with
       // a solution that follows the
       // letter of this silly assignment
       // while making fun of it.
       
       for (N = 1; N <= 1; N++) {
          System.out.println("2 4 6 8 10 12 14 16 18 20");
       }
Perhaps it is worth stressing one more time that a for statement, like any statement, never occurs on its own in a real program. A statement must be inside the main routine of a program or inside some other subroutine. And that subroutine must be defined inside a class. I should also remind you that every variable must be declared before it can be used, and that includes the loop control variable in a for statement. In all the examples that you have seen so far in this section, the loop control variables should be declared to be of type int. It is not required that a loop control variable be an integer. Here, for example, is a for loop in which the variable, ch, is of type char, using the fact that the ++ operator can be applied to characters as well as to numbers:
// Print out the alphabet on one line of output.
char ch;  // The loop control variable; 
          //       one of the letters to be printed.
for ( ch = 'A';  ch <= 'Z';  ch++ )
    System.out.print(ch);
System.out.println();

3.4.2  Example: Counting Divisors

Let's look at a less trivial problem that can be solved with a for loop. If N and D are positive integers, we say that D is a divisor of N if the remainder when D is divided into N is zero. (Equivalently, we could say that N is an even multiple of D.) In terms of Java programming, D is a divisor of N if N % D is zero.
Let's write a program that inputs a positive integer, N, from the user and computes how many different divisors N has. The numbers that could possibly be divisors of N are 1, 2, ..., N. To compute the number of divisors of N, we can just test each possible divisor of N and count the ones that actually do divide N evenly. In pseudocode, the algorithm takes the form
Get a positive integer, N, from the user
Let divisorCount = 0
for each number, testDivisor, in the range from 1 to N:
    if testDivisor is a divisor of N:
        Count it by adding 1 to divisorCount
Output the count
This algorithm displays a common programming pattern that is used when some, but not all, of a sequence of items are to be processed. The general pattern is
for each item in the sequence:
   if the item passes the test:
       process it
The for loop in our divisor-counting algorithm can be translated into Java code as
for (testDivisor = 1; testDivisor <= N; testDivisor++) {
   if ( N % testDivisor == 0 )
      divisorCount++;
}
On a modern computer, this loop can be executed very quickly. It is not impossible to run it even for the largest legal int value, 2147483647. (If you wanted to run it for even larger values, you could use variables of type long rather than int.) However, it does take a significant amount of time for very large numbers. So when I implemented this algorithm, I decided to output a dot every time the computer has tested one million possible divisors. In the improved version of the program, there are two types of counting going on. We have to count the number of divisors and we also have to count the number of possible divisors that have been tested. So the program needs two counters. When the second counter reaches 1000000, the program outputs a '.' and resets the counter to zero so that we can start counting the next group of one million. Reverting to pseudocode, the algorithm now looks like
Get a positive integer, N, from the user
Let divisorCount = 0  // Number of divisors found.
Let numberTested = 0  // Number of possible divisors tested
                      //       since the last period was output.
for each number, testDivisor, in the range from 1 to N:
    if testDivisor is a divisor of N:
        Count it by adding 1 to divisorCount
    Add 1 to numberTested
    if numberTested is 1000000:
        print out a '.'
        Reset numberTested to 0
Output the count
Finally, we can translate the algorithm into a complete Java program. Here it is, followed by an applet that simulates it:
/**
 * This program reads a positive integer from the user.
 * It counts how many divisors that number has, and
 * then it prints the result.
 */
   
public class CountDivisors {
   
   public static void main(String[] args) {
      
      int N;  // A positive integer entered by the user.
              // Divisors of this number will be counted.
              
      int testDivisor;  // A number between 1 and N that is a
                        // possible divisor of N.
      
      int divisorCount;  // Number of divisors of N that have been found.
      
      int numberTested;  // Used to count how many possible divisors
                         // of N have been tested.  When the number
                         // reaches 1000000, a period is output and
                         // the value of numberTested is reset to zero.
                         
      /* Get a positive integer from the user. */
   
      while (true) {
         System.out.print("Enter a positive integer: ");
         N = TextIO.getlnInt();
         if (N > 0)
            break;
         System.out.println("That number is not positive.  Please try again.");
      }
      
      /* Count the divisors, printing a "." after every 1000000 tests. */
    
      divisorCount = 0;
      numberTested = 0;
      
      for (testDivisor = 1; testDivisor <= N; testDivisor++) {
         if ( N % testDivisor == 0 )
            divisorCount++;
         numberTested++;
         if (numberTested == 1000000) {
            System.out.print('.');
            numberTested = 0;
         }
      }
      
      /* Display the result. */
      
      System.out.println();
      System.out.println("The number of divisors of " + N
                          + " is " + divisorCount);
      
   } // end main()
   
} // end class CountDivisors

3.4.3  Nested for Loops

Control structures in Java are statements that contain statements. In particular, control structures can contain control structures. You've already seen several examples of if statements inside loops, and one example of a while loop inside another while, but any combination of one control structure inside another is possible. We say that one structure is nested inside another. You can even have multiple levels of nesting, such as a while loop inside an if statement inside another while loop. The syntax of Java does not set a limit on the number of levels of nesting. As a practical matter, though, it's difficult to understand a program that has more than a few levels of nesting.
Nested for loops arise naturally in many algorithms, and it is important to understand how they work. Let's look at a couple of examples. First, consider the problem of printing out a multiplication table like this one:
 1   2   3   4   5   6   7   8   9  10  11  12
 2   4   6   8  10  12  14  16  18  20  22  24
 3   6   9  12  15  18  21  24  27  30  33  36
 4   8  12  16  20  24  28  32  36  40  44  48
 5  10  15  20  25  30  35  40  45  50  55  60
 6  12  18  24  30  36  42  48  54  60  66  72
 7  14  21  28  35  42  49  56  63  70  77  84
 8  16  24  32  40  48  56  64  72  80  88  96
 9  18  27  36  45  54  63  72  81  90  99 108
10  20  30  40  50  60  70  80  90 100 110 120
11  22  33  44  55  66  77  88  99 110 121 132
12  24  36  48  60  72  84  96 108 120 132 144
The data in the table are arranged into 12 rows and 12 columns. The process of printing them out can be expressed in a pseudocode algorithm as
for each rowNumber = 1, 2, 3, ..., 12:
   Print the first twelve multiples of rowNumber on one line
   Output a carriage return
The first step in the for loop can itself be expressed as a for loop. We can expand "Print the first twelve multiples of rowNumber on one line" as:
for N = 1, 2, 3, ..., 12:
   Print N * rowNumber
so a refined algorithm for printing the table has one for loop nested inside another:
for each rowNumber = 1, 2, 3, ..., 12:
   for N = 1, 2, 3, ..., 12:
      Print N * rowNumber
   Output a carriage return
We want to print the output in neat columns, with each output number taking up four spaces. This can be done using formatted output with format specifier %4d. Assuming that rowNumber and N have been declared to be variables of type int, the algorithm can be expressed in Java as
for ( rowNumber = 1;  rowNumber <= 12;  rowNumber++ ) {
   for ( N = 1;  N <= 12;  N++ ) {
               // print in 4-character columns
      System.out.printf( "%4d", N * rowNumber );  // No carriage return !
   }
   System.out.println();  // Add a carriage return at end of the line.
}
This section has been weighed down with lots of examples of numerical processing. For our next example, let's do some text processing. Consider the problem of finding which of the 26 letters of the alphabet occur in a given string. For example, the letters that occur in "Hello World" are D, E, H, L, O, R, and W. More specifically, we will write a program that will list all the letters contained in a string and will also count the number of different letters. The string will be input by the user. Let's start with a pseudocode algorithm for the program.
Ask the user to input a string
Read the response into a variable, str
Let count = 0  (for counting the number of different letters)
for each letter of the alphabet:
   if the letter occurs in str:
      Print the letter
      Add 1 to count
Output the count
Since we want to process the entire line of text that is entered by the user, we'll use TextIO.getln() to read it. The line of the algorithm that reads "for each letter of the alphabet" can be expressed as "for (letter='A'; letter<='Z'; letter++)". But the body of this for loop needs more thought. How do we check whether the given letter, letter, occurs in str? One idea is to look at each character in the string in turn, and check whether that character is equal to letter. We can get the i-th character of str with the function call str.charAt(i), where i ranges from 0 to str.length() - 1.
One more difficulty: A letter such as 'A' can occur in str in either upper or lower case, 'A' or 'a'. We have to check for both of these. But we can avoid this difficulty by converting str to upper case before processing it. Then, we only have to check for the upper case letter. We can now flesh out the algorithm fully:
Ask the user to input a string
Read the response into a variable, str
Convert str to upper case
Let count = 0
for letter = 'A', 'B', ..., 'Z':
    for i = 0, 1, ..., str.length()-1:
        if letter == str.charAt(i):
            Print letter
            Add 1 to count
            break  // jump out of the loop, to avoid counting letter twice
Output the count
Note the use of break in the nested for loop. It is required to avoid printing or counting a given letter more than once (in the case where it occurs more than once in the string). The break statement breaks out of the inner for loop, but not the outer for loop. Upon executing the break, the computer continues the outer loop with the next value of letter. You should try to figure out exactly what count would be at the end of this program, if the break statement were omitted.
Here is the complete program and an applet to simulate it:
/**
 * This program reads a line of text entered by the user.
 * It prints a list of the letters that occur in the text,
 * and it reports how many different letters were found.
 */

public class ListLetters {
   
   public static void main(String[] args) {
   
      String str;  // Line of text entered by the user.
      int count;   // Number of different letters found in str.
      char letter; // A letter of the alphabet.
      
      TextIO.putln("Please type in a line of text.");
      str = TextIO.getln();
      
      str = str.toUpperCase();
      
      count = 0;
      TextIO.putln("Your input contains the following letters:");
      TextIO.putln();
      TextIO.put("   ");
      for ( letter = 'A'; letter <= 'Z'; letter++ ) {
          int i;  // Position of a character in str.
          for ( i = 0; i < str.length(); i++ ) {
              if ( letter == str.charAt(i) ) {
                  TextIO.put(letter);
                  TextIO.put(' ');
                  count++;
                  break;
              }
          }
      }
      
      TextIO.putln();
      TextIO.putln();
      TextIO.putln("There were " + count + " different letters.");
   
   } // end main()
   
} // end class ListLetters
In fact, there is actually an easier way to determine whether a given letter occurs in a string, str. The built-in function str.indexOf(letter) will return -1 if letter does not occur in the string. It returns a number greater than or equal to zero if it does occur. So, we could check whether letter occurs in str simply by checking "if (str.indexOf(letter) >= 0)". If we used this technique in the above program, we wouldn't need a nested for loop. This gives you a preview of how subroutines can be used to deal with complexity.

3.4.4  Enums and for-each Loops

Java 5.0 introduced a new "enhanced" form of the for loop that is designed to be convenient for processing data structures. A data structure is a collection of data items, considered as a unit. For example, a listis a data structure that consists simply of a sequence of items. The enhanced for loop makes it easy to apply the same processing to every element of a list or other data structure. Data structures are a major topic in computer science, but we won't encounter them in any serious way until Chapter 7. However, one of the applications of the enhanced for loop is to enum types, and so we consider it briefly here. (Enums were introduced in Subsection 2.3.3.)
The enhanced for loop can be used to perform the same processing on each of the enum constants that are the possible values of an enumerated type. The syntax for doing this is:
for ( enum-type-name  variable-name  :  enum-type-name.values() )
   statement
or
for ( enum-type-name  variable-name  :  enum-type-name.values() ) {
   statements
}
If MyEnum is the name of any enumerated type, then MyEnum.values() is a function call that returns a list containing all of the values of the enum. (values() is a static member function in MyEnum and of any other enum.) For this enumerated type, the for loop would have the form:
for ( MyEnum  variable-name  :  MyEnum.values() )
   statement
The intent of this is to execute the statement once for each of the possible values of the MyEnum type. The variable-name is the loop control variable. In the statement, it represents the enumerated type value that is currently being processed. This variable should not be declared before the for loop; it is essentially being declared in the loop itself.
To give a concrete example, suppose that the following enumerated type has been defined to represent the days of the week:
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
Then we could write:
for ( Day d : Day.values() ) {
   System.out.print( d );
   System.out.print(" is day number ");
   System.out.println( d.ordinal() );
}
Day.values() represents the list containing the seven constants that make up the enumerated type. The first time through this loop, the value of d would be the first enumerated type value Day.MONDAY, which has ordinal number 0, so the output would be "MONDAY is day number 0". The second time through the loop, the value of d would be Day.TUESDAY, and so on through Day.SUNDAY. The body of the loop is executed once for each item in the list Day.values(), with d taking on each of those values in turn. The full output from this loop would be:
MONDAY is day number 0
TUESDAY is day number 1
WEDNESDAY is day number 2
THURSDAY is day number 3
FRIDAY is day number 4
SATURDAY is day number 5
SUNDAY is day number 6
Since the intent of the enhanced for loop is to do something "for each" item in a data structure, it is often called a for-each loop. The syntax for this type of loop is unfortunate. It would be better if it were written something like "foreach Day d in Day.values()", which conveys the meaning much better and is similar to the syntax used in other programming languages for similar types of loops. It's helpful to think of the colon (:) in the loop as meaning "in."