Lesson 7.2 Runtime Errors
That "stern and pedantic taskmaster," the Java compiler, always tells you when you've made a mistake, even if you don't understand its error messages. Unfortunately, the Java compiler is unable to catch all of your errors because it cannot, among other things, read your mind.
Runtime errors are the errors that occur when you try to run your program. Runtime errors really come in three varieties:
- For some errors, the Java Virtual Machine will step in and tell you that you've done something wrong. Like syntax errors, such "program crashes" are often annoying, but ultimately for the best.
- For other errors, the JVM is unable to print an error message, but your program just quits working altogether. With such hanging programs, it's obvious that something is wrong, but, other than the symptoms, you receive no other help in solving the problem.
- The last group of errors, the really difficult errors, occur silently and without warning. These logical errors are those that cause your program to behave incorrectly, but, unless you're on the lookout, you might not even notice that anything is wrong.
Runtime Exceptions
Runtime exceptions are nice for two reasons.
- First, when a runtime exception occurs, the Java Virtual Machine [JVM] notices that something is wrong, and it makes an effort to notify you.
- Second, Java's exception-handling mechanism allows you to intercept and handle runtime exceptions. You'll learn more about the exception mechanism and how to put it to work in the next two sections in this lesson.
Let's see what a runtime exception looks like.
Here's the applet, RuntimeError, from Chapter 7 in the textbook. Before you jump on ahead, and start pressing it's buttons, take a moment to open your browser's Java Console window, or use the Appletviewer to run the program. If you use Appletviewer, the error messages will show up in the Command Window that starts the Appletviewer program.
This applet, RuntimeError.java allows the user to trigger three types of runtime errors by pressing an appropriate button [as discussed in the lesson].
NullPointerException
Once your Java console is open, go ahead an press the "Nobody's Home" button. You'll see something that looks like this:
As you can see from the JVM's error message, the error is a NullPointerException and the problem occurs in RuntimeError's tryNull() method, at line 49.
Here is the code for the tryNull() method:
|
RuntimeError.tryNull()
|
void tryNull()
{
b.setLabel("Uh Oh!");
} |
Looking at this code, it's not immediately obvious what the problem is. We could trace back through the code to the actionPerformed() method that called tryNull(), but that still won't lead us to the problem.
Instead, you have to understand what NullPointerException means. A NullPointerException is Java's way of saying: "This object variable doesn't refer to a real object." You can't send a setLabel() message to a Button object that doesn't exist, and so the JVM simply steps in and prints an error message.
Remember, anytime you see a NullPointerException, it really means "Unititialized Object." Looking back through the code to where the Button variable b is defined you'll find:
Button b; // This has the value null
ArithmeticException
When you press the "Problems with Math" button, your Java Console window will look something like this:
Java's VM throws an ArtithmeticException whenever you ask it to perform an illegal artithmetic operation. As you can see from the message, the error occurred in the divideZero() method. If you pull up the method, which is shown here, you can see that, sure enough, the program attempts the impossible:
|
RuntimeError.divideZero()
|
void divideZero()
{
int numerator = 3;
int denominator = 0;
int problem = numerator / denominator;
} |
Unlike NullPointerException, the ArtithmeticException is usually not a puzzle when it occurs. The solution, too, is usually stratightforward: "don't do that". With careful programming you should be able to eliminate this exception.
NumberFormatException
The third runtime error exposed by the RuntimeError applet is a little different than the other two. Java generates a NullPointerException in an attempt to protect the integrity of the JVM, and it throws an ArtithmeticException to protect the integrity of the mathematical universe as we know it.
The last runtime error generated by this applet falls into neither of these categories. If you press the "How Much is a Cat" button, Java generates a message that says, essentially, "I don't know how to do that:"
Following the line numbers, you can see that the error occurs in the Integer.parseInt() method--a method in the standard Java class library. Both of the previous runtime errors were intrinsic runtime errors--errors generated directly by the JVM. This is not.
If you trace back from where the original error occurred, you find that the method convertCat() was the last time that RuntimeError.java had hold of the code. Let's take a look:
|
RuntimeError.convertCat()
|
void convertCat()
{
String num = "Cat";
int bad = Integer.parseInt( num );
} |
As you can see, the error is caused by asking the Integer class to convert the String "Cat" into an int. This is not an impossible task--at least not impossible in the same sense that dividing by zero is impossible.
It is also harder to protect against. As you found out in Homework 2, "CalcIt", when you get input from your users, they can type, essentially, anything into a TextField. When you convert the text contained into that TextField to a number, it is almost impossible to first check the contents of the TextField to be sure that the conversion will succeed.
For that reason, Java provides a way to recover from this sort of runtime error--the try-catch mechanism. You'll learn how to apply try-catch later in this unit.
Hanging Programs
Programs that stop responding are called hanging programs. It's obvious, when you run such a program, that something is wrong. Discovering what the problem is, and fixing it, however, is sometimes a little more difficult. Knowing about the most common reasons for hanging programs helps.
Hanging programs usually stop responding for one of two reasons:
- You've written an "endless" or "dead" loop.
- You have a "system" error.
Endless Loops
Endless loops are the most common reason for your program to hang. To avoid endless loops in your program, double check for the unavoidable condition that you met in Lessons 5 and 6.
Remember that an unavoidable condition is one where the loop is always entered and is impossible to exit. An unavoidable condition almost always involves confusing the AND and OR operators in a compound boolean condition like this program which, supposedly, collects pension payments from employees between 21 and 65, and, then, at age 65, disburses the payments:
int age = getAge();
while (age >= 21 || age < 65)
{
makePensionContribution();
age++;
}
getPensionPayout(); |
What actually happens is that, because the programmer used OR instead of AND, the program collects pension contributions forever, but never pays out a dime. There is one other situation where an endless or semi-endless loop is common in Java programs--wayward animation attempts.
Wayward Animation
Often, programmers will attempt to create an animation loop inside the paint() method like this:
|
An Unsuccessful Animation Attempt
|
public void paint(Graphics g)
{
int x = getSize().width / 2;
int y = getSize().height / 2;
int dx = 5, dy = 5;
while (true)
{
x += dx;
y += dy; if (x > getSize().width || x < 0)
dx = -dx;
if (y > getSize().height || y < 0)
dy = -dy;
g.drawString("@", x, y);
}
}
|
This loop attempts to move a bouncing @ around the screen. The problem is that, under normal operations, the paint() method never actually display its ouput on the screen. This "display updating" occurs "behind the scenes" after the paint() method is finished. By coding an endless loop inside the paint() method, your program never gives Java's background tasks a chance to run. If you create an applet using this code, and then run it in appletviewer, you'll see that you won't even be able to close the appletviewer window by clicking on the close button. Java doesn't have any time to pay attention to the close button because you're hogging all of its attention.
System Errors
In addition to hanging because of an endless loop, your program might also hang because of a "system error." This catchall phrase covers a lot of ground. Most of the time, the system error really doesn't have anything to do with your program at all, and there's nothing you can do about it. Sometimes, though, you can change something in your program that will prevent the system error from occurring.
Most system errors, at least those where the system hangs, occur for one of two reasons:
- A necessary computer resource is depleted.
- Multiple programs have deadlocked waiting for access to the same resource.
An example of a system resource is the Graphics class. If you confine your use of the Graphics class to the Graphics object you receive in the paint() method, you won't have any problems. If, however, you use the Component getGraphics() method to draw outside of the paint() method, without calling the dispose() method after your are finished, you may exhaust your operating system's supply of graphic device contexts. When this happens, your Java program becomes unable to repaint itself. It doesn't hang, exactly, but for all intents and purposes, it's dead.
Other resources that are often similarly limited and that can result in similar resource depletion include Color objects, threads, streams, and network connections. Deadlock occurs when two processes both attempt to acquire a resource used by the other. If you have an input and output file, for instance, one program may open the input file first, while the other opens the output file first. Both programs can get stuck and wait forever for the other program to give up the resource which it needs. Deadlock is common when it comes to writing multi-threaded programs. You can read more about deadlock and some preventative techniques in Chapter 15 of your textbook.
Regaining Control
When your program goes into an endless loop, or when you run out of memory or Graphics objects, what can you do? There's no hard and fast answer, but you should start with the least drastic remedy before you resort to pulling the plug or pulling out the sledgehammer.
Here are some suggestions:
- Try the "Stop," "Exit," or "Quit" button included in your applet or GUI application. Try to load a different page into your browser. Click the CLOSE icon in the upper left corner of appletviewer or your GUI application’s window. Make the MS-DOS window you used to start appletviewer or the MS-DOS window of your application the current window by clicking on its title bar. Then type CTRL-C, by holding down the CTRL key and simultaneously pressing the c key. This should "cancel" or terminate the program. Exit your browser. Use CTRL-ALT-DELETE to cancel the task. Shut down your computer.
- When all else fails, cycle power to your computer. This may result in serious loss of data, so it’s definitely a last resort.
Logical Errors
Logical errors are different than the other errors we've discussed up to this point. It's not just that logical errors are harder to correct--and they are--it's that it is incredibly difficult to discover that an error has occurred at all. In fact, an entire phase of the software development cycle--the testing phase--is devoted to discovering hidden, unrevealed errors.
You'll read more about testing your software in "Testing and Debugging." Before you can even think about testing your software, however, you must have some idea of what it is supposed to do. The process of testing begins with a precise and unambiguous description of your program's correct behavior. This description is called the program specification.
Something to Talk AboutLook at the code displayed under "A Wayward Animation". What steps would you take to make the code actually bounce the @ around the screen? [You don't have to write the code; just tell us what you would do in general terms.]
Please continue to the next section of this lesson.
|