Welcome to the Computing Concepts with Java Essentials FAQ!

{short description of image}

This page refers to the out-of-print first edition of the book. There is now a second edition.

Question: Why do I have to deal with the stupid ccj package? Can't you just teach standard Java?

Answer: The ccj package supports five different services.

  1. Console input
  2. Simple graphics
  3. The Employee and Time classes that are used for many examples
  4. Five convenience functions in the Numeric class
  5. Formatted output

Let's take these up one at a time.

  1. It is surprisingly difficult in Java to read numbers from the keyboard in console programs (programs without a graphical user interface). This is discussed in gory detail below. I didn't want to supply a proprietary mechanism, but felt it was the lesser evil. If you don't like the Console class, you can avoid it (see below).
  2. Students like graphics. However, graphics programming in Java is a challenge for two reasons. First, there are now three incompatible user interface toolkits, with Java 1.0, 1.1 and 1.2. Which one should you teach to? How do you deal with students whose compilers don't support your choice? Second, how do you introduce students to the complexities of event handling and user interface layout?
    The ccj graphics are, I think, a reasonable solution. They are independent of the Java version and take care of event handling. You'll find more information below.
  3. The example classes aren't really library services; the library was just a convenient place to put them.
  4. You can easily avoid the five convenience functions in the Numeric class--appendix A2.15 shows how.
  5. Java 1.0 has no solution for formatted output. The solution in Java 1.1 is complex. Only a small number of examples in the book use formatted output. You can skip those if you like.

Question: What versions of Java does the ccj package support?

Answer: The ccj package works with Java 1.0, 1.1 and 2. The book shields students from the details of Java event handling and UI design (which changed dramatically between Java 1.0, 1.1 and 2).

Question: Why do I get warnings about deprecated API calls?

Answer: You are using Java 1.1. The ccj package implementation makes calls to the 1.0 API so that users who still have the older version of Java can also use it. The warnings are harmless and you can safely ignore them. Eventually, I will create a version of the library for Java 1.1 (or 1.2), but that creates a different problem--if students use a mixture of environments, then they may accidentally pick up a library that doesn't work on their system. At this point, I consider a library that gives harmless warnings on some systems superior to a library that doesn't work on some some systems.

Question: I am using Java 2 and the applet viewer doesn't work even though I set my class path right.

Answer: This is an "improvement" in the applet viewer. The applet viewer no longer looks at the class path. The intent is that the applet viewer should mimic a browser. There are three remedies:

  1. (Tedious but politically correct). Place a subdirectory ccj under every directory that contains your applets, and copy all the .class files from the ccj package into each of these subdirectories.
  2. (Weird). Start the applet viewer in debug mode, like this:
    echo run | appletviewer -debug LineTest.html
    
  3. (Sneaky). Use the unpublished -nosecurity flag, like this:
    java sun.applet.AppletViewer -nosecurity LineTest.html

Question: I am using javac under Windows, and my program has so many errors that they all flash by and I can only see the last few. I even tried redirection (javac MyProg.java | more or javac MyProg.java > errors.txt), and it doesn't work.

Answer: The javac compiler sends error messages to the standard error stream, not the standard output stream. Unfortunately, the Windows shell does not allow redirection of the standard error stream to a file.

Remedy: Use the errout.exe program to redirect the standard error stream to the standard output stream:

errout javac MyProg.java | more
errout javac MyProg.java > errors.txt

This is a simple C program--source code below:

#include <io.h>
#include <stdio.h>
#include <process.h>

int main(int argc, char* argv[])
{  dup2(1, 2); // make stderr go to stdout
   execvp(argv[1], argv + 1);
   return 0;
}

Or, if you prefer a pure Java solution, compile the following Java class:

import java.io.*;

public class Errout
{  public static void main(String[] args) throws IOException
   {  Process p = Runtime.getRuntime().exec(args);
      BufferedReader err
         = new BufferedReader(new InputStreamReader(p.getErrorStream()));
      String line;
      while ((line = err.readLine()) != null)
         System.out.println(line);
   }
}

Then execute the following command:

java Errout javac MyProg.java | more
java Errout javac MyProg.java > errors.txt

Question: My compiler gives a warning at the line for (;;) in TextInputStream.

This is a bug in the Supercede compiler from Asymetrix. Ignore it.

I didn't want to patch the code to make the Supercede compiler happy, because then other compilers will start complaining about "unreachable code".

Question: The compiler can't find the ccj classes. What can I do?

Answer: I realize that this can be frustrating--the current crop of Java compilers isn't yet as user-friendly as one would like. Here are some suggestions to try.

  1. Call the vendor of your compiler. Adding a package to the class path is not some exotic operation. If your compiler doesn't read the DOS/Unix class path and does not have an obvious way of adding packages, then bug them and have them walk you through the procedure. It was their fault for making a common task difficult.
  2. Check the class path. Pay attention to / vs. \, capitalization, confusing spaces, the order of the items, the presence of the current directory (.), the presence of other possibly interfering paths. Make sure not to include the ccj subdirectory into the class path! If the class path is in order, then your compiler is broken in some way--every compiler should read the class path environment variable. Reconsider carrying out step 1.
  3. Add the classes locally. This should always work. The "Hello, World" test shows that the current directory is on the class path. By placing the ccj files in a subdirectory of a directory in the class path (i.e. the current directory), the compiler ought to locate them. The only drawback of this method is that you have to replicate this for every directory containing files for the book. (You can have multiple programs in one directory, as long as they do not have conflicting class names.) If you don't mind the inelegance of this process, stop right here.
  4. Once loading of the classes works and you have some confidence that life is worth living again, try doing it the right way. Add the classes to a subdirectory ccjof a new directory (say c:\CCJBook) , and add that directory (c:\CCJBook) onto the class path. Make sure not to include the ccj into the class path!
  5. If that doesn't work, try zipping up all files in the c:\CCJBook directory. Be careful that the root of the ZIP operation is c:\CCJBook, not c:\CCJBook\ccj. And be sure that the ZIP program includes the subdirectory paths into the ZIP file. Name the ZIP file ccj.zip and add c:\CCJBook\ccj.zip to the class path. If that doesn't work, try renaming the file to classes.zip.
  6. If that doesn't work, curse your compiler vendor and try adding the classes to the system classes. Locate the file classes.zip from which the compiler reads the Java classes. Make a backup of that file and put the backup into a safe place.Unzip it into a temporary directory. Add a subdirectory ccj off that temporary directory and add the ccj class files. Zip everything back up. Naturally, this operation should be carried out by trained professionals only.

Question: How can I make a console program pause before quitting?

Answer: You would want to do this if your integrated development environment immediately closes a console application when it has completed, giving you no chance to admire the output.

The following method always works. Add these lines to the end of your program:

System.out.println("To quit, type any character, then [Enter]");
String s = Console.in.readWord();

Then you type any character (such as Q), then hit the [Enter] key.

Of course, it would be nicer if you could just hit the [Enter] key. That, unfortunately, is a little harder. You can't just call readLine to read an empty line. because readInt/readDouble doesn't mix well with readLine (see Common Error 6.2).

You must look at your program. If all input in the program used readInt/readDouble/readWord, you can add the following lines to the end of your program:

String s = Console.in.readLine(); /* consume trailing '\n' */
System.out.println("To quit, type [Enter]");
String s = Console.in.readLine();

If all input in the program used readLine/readChar, instead add the following lines to the end of your program:

System.out.println("To quit, type [Enter]");
String s = Console.in.readLine();

Question: How can I print my homework?

Answer: Here are directions for Windows 95/NT.

  1. If your program is a graphics program, then run it and take a screen snapshot by hitting Alt+Print Screen. Paste the graphics into a paint program (such as MS Paint) or word processor by typing Ctrl+V, then print it.
  2. If your program is a text program, and the input and output fits on a single screen, you can use the same method for taking a screen snapshot of a DOS shell window.
  3. If your program has no input but lots of output, you can redirect the output to a file (see Productivity Hint 6.1) and then print the output file. But that doesn't work if you also need type input because you won't see the prompts.
  4. If your program has both lots of input and output, I don't know a good solution. You can place all inputs into a file, redirect both input and output, and print both the input and output files. But then the input and output won't appear together.

I don't have information for other operating systems, but I will gladly publish them if someone lets me know. Frankly, whenever I teach programming courses, I collect the programs on disk or via email and run them myself--it is a simple matter for students to edit a text or image file before printing it out.

Question: Why do you supply a Console package for reading input?

Answer: I wish I didn't have to. Java offers very poor handling for text input. It simply wasn't something the designers cared about. Here is what you'd have to to read a floating-point number in plain Java:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
/* in Java 1.0, use DataInputStream in = new DataInputStream(System.in) instead */
double x = 0;
try
{  String s = in.readLine();
   x = new Double(s.trim()).doubleValue();
} catch(IOException e) {}

Using the ccj package, this becomes simply

double x = Console.in.readDouble();

That is, Console.in is just like System.in, except that it has a friendlier interface.

I realize that this means that your students don't learn standard Java. If this really bothers you, you can avoid the console package as follows:

  1. Add the line
    public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    /* in Java 1.0, use DataInputStream in = new DataInputStream(System.in) instead */
    
    into each program that needs to read from the console.
  2. Add throws IOException to each function that reads input, and to all its callers (including main).
  3. Read from in, not Console.in
  4. First read into a string, then convert to a number:
    int n = Integer.parseInt(in.readLine().trim());
    double x = new Double(in.readLine().trim()).doubleValue(); 

For example,

import java.io.*;

public class Test
{  public static void main(String[] args) throws Exception
   {  System.out.print("Please enter a number: ");
      double x = new Double(in.readLine().trim()).doubleValue();
      System.out.println(x);
   }
   public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
}

Question: When reading a number from a TextInputStream, a trailing newline character is not consumed. That means I can't mix readInt and readLine.

Answer: This is a design feature, but perhaps, from the hate mail I get, not a popular one.

I was already uncomfortable introducing a new input mechanism, and I decided to at least make it compatible with the well-known mechanisms in C++ and C. That is, the Console input functions consume exactly as many characters as their following C++ and C equivalents:

ccj C++ C
n = Console.in.readInt() cin >> n scanf("%d", &n)
x = Console.in.readDouble() cin >> x scanf("%f", &x)
s = Console.in.readWord() cin >> s scanf("%s", &s)
s = Console.in.readLine() getline(cin, s) fgets(s, stdin)
s = Console.in.readChar() cin.get(ch); ch = fgetc(stdin);

The first three functions consume leading white space, but they don't consume trailing white space.

So what?

As a consequence, you can't mix readInt and readLine. This is explained in Common Error 6.2.

Consider the following:

System.out.print("Please enter a number: ");
int x = Console.in.readInt();
System.out.print("More? (Y/N) ");
String more = Console.in.readLine(); /* NO! */

This won't work--readInt looks at, but doesn't consume, the final newline in its input line. readLine reads the remainder of the current input line.

There are two remedies. Switch to a different text book. (One professor was sufficiently enraged about this issue that he is planning to do just that.). Or call readWord instead of readLine.

System.out.print("Please enter a number: ");
int x = Console.in.readInt();
System.out.print("More? (Y/N) ");
String more = Console.in.readWord(); /* OK! */

This is, of course, exactly the same as in C or C++, but that comes as little consolation to those who are abandoning those languages in favor of Java.

I am not at all sure what I should do about this in the second edition of this book, and I very much welcome advice.

In Core Java, I implemented static readInt/readDouble methods that do the following:

  1. Display a prompt on System.out
  2. Read a line of input from System.in
  3. If it isn't a number, repeat
  4. Return the number

For example,

int x = Numeric.readInt("Please enter a number");

This works great--all the issues about white space, bad stream state, and so on, simply go away. I decided against this approach in ccj because it turns input into even more of a black box. The current ccj approach at least offers an easy migration strategy to plain Java.

Let me know what you think!

Question: When reading bad input from a TextInputStream, the stream stops reading input. How can I make it read again?

Answer: You can't.

The TextInputStream class was designed to work this way. If you want to make your input more robust, read the input a line at a time, and analyze each input line separately. See section 6.3.2 for a typical example.

I could have designed the class differently. I was motivated by two reasons:

  1. The C++ input streams use this failure mechanism. Since many programmers need to use both C++ and Java, it seemed reasonable to follow an established mechanism rather than inventing yet another one.
  2. The standard Java mechanism would be to throw an exception, but I did not want to introduce the complexity of exception handling at a very early stage of programming.

You may wonder why the C++ stream library makes the decision to set the stream to a failed state as soon as one input is bad. Here is the reason. Some kinds of streams (for example redirected input or input from a network connection) do not allow arbitrary lookahead. You can read one character and put it back if you don't like it, but you can't put back multiple characters. That is, some characters may be consumed when an error is detected. Consider the following:

double x = Console.in.readDouble();


Sample inputs:

In general, it will be very difficult for a program to make any intelligent decision whether to keep reading input.

Of course, when the input comes from a person, and there was a mechanism for resetting the stream state, a program could read all characters up the end of the line, and ask the person to type in the input line again. And when the input comes from a file, the program could potentially skip one data set and keep on reading. Should the TextInputStream support this kind of programming? Right now, it doesn't, and you need to use readLine (which is a standard Java function).

Should I add a different nonstandard mechanism? If there was such a mechanism, would students learn more computing concepts when they use it in their code? Should students learn how to handle input error recovery in console input? After all, in later semesters they will never need this skill again--input will come either from a file or a GUI text field. Please let me know if you have an opinion on this.

Question: What support materials are available for the book?

Answer:

Question: How can I get the solutions to the exercises?

Answer: If you are an instructor, please visit http://www.wiley.com/college/horstmannjava/ and select "Instructor Resources". You will need to fill out a form and obtain a password to see the solutions. If you are not an instructor, unfortunately you cannot get that material. Clearly, instructors would be upset if students could purchase solutions manuals and simply copy the answers instead of doing the work themselves. Therefore, solutions guides have a restricted distribution. I realize that this may be upsetting if you purchased this book for self-study.

Question: I am an instructor and have a password to the solution site. Why do I have to keep coming back to look up each question separately?

Answer: Several people have requested a ZIP file with all answers.

Imagine the following scenario:

As any publisher knows, this is an all too common scenario. Intellectual property is stolen on the internet with distressing regularity. And it is essentially impossible to get a law enforcement agency in another country to act in what they understandably perceive as a minor violation of the law.

We felt that putting the questions on a password-protected web site was a good compromise. As an instructor who needs to look up a few solutions per week, you will not be greatly inconvenienced. Of course, you can save or print individual answers, as needed.

Question: Why do you supply your own graphics package instead of using the AWT?

Answer: Students enjoy programming with graphics, but the AWT graphics are neither object-oriented nor convenient. Consider the following simple assignment: Write a program that prompts the user to click on two points and then joins them with a line segment.

Here is the solution with the graphics support in the ccj package.

import ccj.*;

public class Sample extends GraphicsApplet
{	 public void run()
  	{  Point p = getMouse("Please enter the first point");
      p.draw();
    		Point q 	= getMouse("Please enter the second point");
      q.draw();
    		Line l = new Line(p, q);
   		 l.draw();
  	}
}

Here is the same program using nothing but AWT 1.1.

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Sample extends Applet
{  public Sample()
   {  clickCount = 0;
      message = new TextField("Please enter the first point");
      setLayout(new BorderLayout());
      add(message, "South");
      addMouseListener(new MouseAdapter()
         {  public void mouseClicked(MouseEvent evt)
            {  clickCount++;
               if (clickCount == 1)
               {  xfrom = evt.getX();
                  yfrom = evt.getY();
                  message.setText("Please enter the second point");
               }
               else if (clickCount == 2)
               {  xto = evt.getX();
                  yto = evt.getY();
                  message.setText("");
               }
               repaint();
            }
         });
   }


   public void paint(Graphics g)
   {  if (clickCount >= 1)
      {  g.drawOval(xfrom - POINT_RADIUS, yfrom - POINT_RADIUS,
            2 * POINT_RADIUS + 1, 2 * POINT_RADIUS + 1);
      }
      if (clickCount >= 2)
      {  g.drawOval(xto - POINT_RADIUS, yto - POINT_RADIUS,
            2 * POINT_RADIUS + 1, 2 * POINT_RADIUS + 1);
         g.drawLine(xfrom, yfrom, xto, yto);
      }
   }

   public static final int POINT_RADIUS = 2;
   private int clickCount;
   private int xfrom, yfrom, xto, yto;
   private TextField message;
}

The defense rests.

Question: Why doesn't the book teach event handling? Doesn't every Java programmer need to know how to handle events?

Answer: This is a book about computing concepts, not about writing Java applets. There are many excellent Java books on the market. (Only modesty prevents me from mentioning the bookCore Java by myself and Gary Cornell.) Event handling in Java is complex, especially for beginners. There is no doubt that Java programmers need to master it, but I do not believe that the first programming course is the appropriate place. (This could change in the future when tools become widely available that produce the event handling code automatically, as in Visual Basic.)

Consider this example, from page 28 of an introductory programming book that ought to remain unnamed. (It is Deitel & Deitel).

// Addition program
import java.awt.*; // import the java.awt package
import java.applet.Applet;

public class Addition extends Applet {
   Label prompt;      // prompts user to input
   TextField input;   // input values here
   int number;
   int sum;

   // setup the graphical user interface components
   // and initialize variables
   public void init()
   {  prompt = new Label( "Enter integer and press Enter:" );
      input = new TextField( 10 );
      add( prompt );  // put prompt on applet
      add( input );   // put input on applet
      sum = 0;
   } 

   // process user's action on the input text field
   public boolean action( Event e, Object o)
   {
      number = Integer.parseInt( o.toString() ); // get number
      input.setText( "" );  // clear data entry field
      sum = sum + number;   // add number to sum
      showStatus( Integer.toString( sum ) ); // show result
      return true;
   }
}

This program keeps adding numbers, displaying the total. Unfortunately, it is not a well-written Java applet. Here are a number of obvious flaws:

Java event handling code is complex. When teaching Java to beginners, authors and instructors have three choices:

  1. teach good event handling and have too little time left for other material
  2. teach bad event handling and still confuse the students
  3. teach no event handling

In my book, students learn how to use loops, functions/methods, classes and arrays. With my book, your students might implement the addition program as follows:

public class Addition
{  public static void main(String[] args)
   {  boolean more = true;
      int sum = 0;
      while (more)
      {  System.out.println("Please enter a number, 0 to quit");
         int input = Console.in.readInt();
         if (input != 0) 
         {  sum = sum + input;
            System.out.println(sum);
         }
         else more = false;
      }
   }
}

It isn't flashy, but it does teach students about loops.

Further Information