This page refers to the out-of-print first edition of the book. There is now a second edition.
Answer: The ccj package supports five different services.
Let's take these up one at a time.
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).
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.
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:
echo run | appletviewer -debug LineTest.html
java sun.applet.AppletViewer -nosecurity LineTest.html
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
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".
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.
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();
Answer: Here are directions for Windows 95/NT.
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.
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:
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.
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)); }
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:
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!
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:
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.
Answer:
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.
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.
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.
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:
public void init() { prompt = new Label( "Enter integer and press Enter:" ); input = new TextField( 10 ); input.addActionListener(new ActionListener() { void actionPerformed(ActionEvent e) { number = Integer.parseInt(input.getText()); input.setText( "" ); // clear data entry field sum = sum + number; // add number to sum showStatus( Integer.toString( sum ) ); // show result } }); add( prompt ); // put prompt on applet add( input ); // put input on applet sum = 0; }
Java event handling code is complex. When teaching Java to beginners, authors and instructors have three choices:
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.