Dealing with Errors Core Java

Suppose an error occurs while a Java program is running. The error might be caused by afile containing wrong information, a flaky network connection, or (we hate to mention it)use of an invalid array index or an attempt to use an object reference that hasn’t yet beenassigned to an object. Users expect that programs will act sensibly when errors happen. Ifan operation cannot be completed because of an error, the program ought to either

• Return to a safe state and enable the user to execute other commands; or
• Allow the user to save all work and terminate the program gracefully.

This may not be easy to do, because the code that detects (or even causes) the errorcondition is usually far removed from the code that can roll back the data to a safestate or the code that can save the user’s work and exit cheerfully. The mission ofexception handling is to transfer control from where the error occurred to an errorhandler that can deal with the situation. To handle exceptional situations in your program,you must take into account the errors and problems that may occur. What sortsof problems do you need to consider?

  • User input errors. In addition to the inevitable typos, some users like to blaze theirown trail instead of following directions. Suppose, for example, that a user asks toconnect to a URL that is syntactically wrong. Your code should check the syntax, butsuppose it does not. Then the network layer will complain.
  • Device errors. Hardware does not always do what you want it to. The printer may beturned off. A web page may be temporarily unavailable. Devices will often fail inthe middle of a task. For example, a printer may run out of paper during printing.
  • Physical limitations. Disks can fill up; you can run out of available memory.
  • Code errors. A method may not perform correctly. For example, it could deliverwrong answers or use other methods incorrectly. Computing an invalid array index,trying to find nonexistent entry in a hash table, and trying to pop an empty stackare all examples of a code error.

The traditional reaction to an error in a method is to return a special error code that thecalling method analyzes. For example, methods that read information back from filesoften return a –1 end-of-file value marker rather than a standard character. This can bean efficient method for dealing with many exceptional conditions. Another commonreturn value to denote an error condition is the null reference Unfortunately, it is not always possible to return an error code. There may be no obviousway of distinguishing valid and invalid data. A method returning an integer cannotsimply return –1 to denote the error—the value –1 might be a perfectly valid result.

Instead, as we mentioned back, Java allows every method an alternative exitpath if it is unable to complete its task in the normal way. In this situation, the methoddoes not return a value. Instead, it throws an object that encapsulates the error information.Note that the method exits immediately; it does not return its normal (or any) value. Moreover, execution does not resume at the code that called the method; instead, theexception-handling mechanism begins its search for an exception handler that can dealwith this particular error condition.

Exceptions have their own syntax and are part of a special inheritance hierarchy. Wetake up the syntax first and then give a few hints on how to use this language featureeffectively.

The Classification of Exceptions

In the Java programming language, an exception object is always an instance of a classderived from Throwable. As you will soon see, you can create your own exception classesif the ones built into Java do not suit your needs.

Figure below is a simplified diagram of the exception hierarchy in Java.

Notice that all exceptions descend from Throwable, but the hierarchy immediately splitsinto two branches: Error and Exception.

Exception hierarchy in Java

Exception hierarchy in Java

The Error hierarchy describes internal errors and resource exhaustion inside the Javaruntime system. You should not throw an object of this type. There is little you can do ifsuch an internal error occurs, beyond notifying the user and trying to terminate theprogram gracefully. These situations are quite rare.

When doing Java programming, you focus on the Exception hierarchy. The Exception hierarchyalso splits into two branches: exceptions that derive from Runtime Exception and thosethat do not. The general rule is this: A RuntimeException happens because you made a programmingerror. Any other exception occurs because a bad thing, such as an I/O error,happened to your otherwise good program.

Exceptions that inherit from RuntimeException include such problems as

• A bad cast
• An out-of-bounds array access
• A null pointer access

Exceptions that do not inherit from RuntimeException include

• Trying to read past the end of a file
• Trying to open a malformed URL
• Trying to find a Class object for a string that does not denote an existing class.

The rule “If it is a RuntimeException, it was your fault” works pretty well. You could have avoided that Array IndexOut OfBounds Exception by testing the array index against the array bounds. The NullPointer Exception would not have happened had you checked whether the variable was null before using it.

How about a malformed URL? Isn’t it also possible to find out whether it is “malformed” before using it? Well, different browsers can handle different kinds of URLs. For example, Netscape can deal with a mailto: URL, whereas the applet viewer cannot.

Thus, the notion of “malformed” depends on the environment, not just on your code.

The Java Language Specification calls any exception that derives from the class Error or the class Runtime Exception an unchecked exception. All other exceptions are called checkedexceptions. This is useful terminology that we also adopt. The compiler checks that you provide exception handlers for all checked exceptions.

C++ NOTE: If you are familiar with the (much more limited) exception hierarchy of the standard C++ library, you will be really confused at this point. C++ has two fundamental exception classes, runtime_error and logic _error. The logic _error class is the equivalent of Java’s RuntimeException and also denotes logical errors in the program. The runtime _error class is the base class for exceptions caused by unpredictable problems. It is equivalent toexceptions in Java that are not of type Runtime Exception.

Declaring Checked Exceptions
A Java method can throw an exception if it encounters a situation it cannot handle. The idea is simple: a method will not only tell the Java compiler what values it can return, itis also going to tell the compiler what can go wrong. For example, code that attempts to read from a file knows that the file might not exist or that it might be empty. The code that tries to process the information in a file therefore will need to notify the compiler that it can throw some sort of IOException.

The place in which you advertise that your method can throw an exception is the header of the method; the header changes to reflect the checked exceptions the method can throw. For example, here is the declaration of one of the constructors of the FileInput-Stream class from the standard library.

public FileInputStream(String name) throws FileNotFoundException

The declaration says that this constructor produces a FileInputStream object from a String parameter but that it also can go wrong in a special way —by throwing a File NotFound Exception.

If this sad state should come to pass, the constructor call will not initialize a new FileInput Stream object but instead will throw an object of the FileNot Found Exception class. If it does, then the runtime system will begin to search for an exception handler that knows how to deal with FileNotFound Exception objects.

When you write your own methods, you don’t have to advertise every possible throwable object that your method might actually throw. To understand when (and what) youhave to advertise in the throws clause of the methods you write, keep in mind that an exception is thrown in any of the following four situations:

  • You call a method that throws a checked exception, for example, the FileInputStream constructor.
  • You detect an error and throw a checked exception with the throw statement (we cover the throw statement in the next section).
  • You make a programming error, such as a[-1] = 0 that gives rise to an unchecked exception such as an Array Index Out Of BoundsException.
  • An internal error occurs in the virtual machine or runtime library.

If either of the first two scenarios occurs, you must tell the programmers who will use your method about the possibility of an exception. Why? Any method that throws an exception is a potential death trap. If no handler catches the exception, the current thread of execution terminates.

As with Java methods that are part of the supplied classes, you declare that your method may throw an exception with an exception specification in the method header.

If a method might throw more than one checked exception type, you must list all exceptionclasses in the header. Separate them by a comma as in the following example:

However, you do not need to advertise internal Java errors, that is, exceptions inheriting from Error. Any code could potentially throw those exceptions, and they are entirely beyond your control. Similarly, you should not advertise unchecked exceptions inheriting from RuntimeException.

These runtime errors are completely under your control. If you are so concerned about array index errors, you should spend the time needed to fix them instead of advertising the possibility that they can happen.

In summary, a method must declare all the checked exceptions that it might throw. Unchecked exceptions are either beyond your control (Error) or result from conditions that you should not have allowed in the first place (Run time Exception). If your method fails to faithfully declare all checked exceptions, the compiler will issue an error message.

Of course, as you have already seen in quite a few examples, instead of declaring the exception, you can also catch it. Then the exception won’t be thrown out of the method, and no throws specification is necessary. You see later in this chapter how to decide whether to catch an exception or to enable someone else to catch it.

If you override a method from a superclass, the checked exceptions that the subclass method declares cannot be more general than those of the superclass method. (It is ok to throw more specific exceptions, or not to throw any exceptions in the subclass method.) In particular, if the superclass method throws no checked exception at all, neither can the subclass. For example, if you override JComponent.paint Component, your paint Component method must not throw any checked exceptions, because the superclass method doesn’t throw any.

When a method in a class declares that it throws an exception that is an instance of a particular class, then it may throw an exception of that class or of any of its subclasses. For example, the FileInput Stream constructor could have declared that it throws an IOException. In that case, you would not have known what kind of IOException. It could be a plain IO Exception or an object of one of the various subclasses, such as FileNot FoundException.

C++ NOTE: The throws specifier is the same as the throw specifier in C++, with one important difference. In C++, throw specifiers are enforced at runtime, not at compile time. That is, the C++ compiler pays no attention to exception specifications. But if an exception is thrown in a function that is not part of the throw list, then the unexpected function is called, and, by default, the program terminates.

Also, in C++, a function may throw any exception if no throw specification is given. In Java, a method without a throws specifier may not throw any checked exception at all.

How to Throw an Exception

Let us suppose something terrible has happened in your code. You have a method, readData, that is reading in a file whose header promised Content-length: 1024 but you get an end of file after 733 characters. You decide this situation is so abnormal that you want to throw an exception. You need to decide what exception type to throw. Some kind of IOException would be a good choice. Perusing the Java API documentation, you find an EOFException with the description “Signals that an EOF has been reached unexpectedly during input.” Perfect.

Here is how you throw it:

The EOFException has a second constructor that takes a string argument. You can put this to good use by describing the exceptional condition more carefully.

As you can see, throwing an exception is easy if one of the existing exception classes works for you. In this case:

1. Find an appropriate exception class.
2. Make an object of that class.
3. Throw it.

Once a method throws an exception, the method does not return to its caller. This means that you do not have to worry about cooking up a default return value or an error code.

C++ NOTE: Throwing an exception is the same in C++ and in Java, with one small exception. In Java, you can throw only objects of subclasses of Throwable. In C++, you can throw values of any type.

Creating Exception Classes

Your code may run into a problem that is not adequately described by any of the standard exception classes. In this case, it is easy enough to create your own exception class. Just derive it from Exception or from a child class of Exception such as IOException. It is customary to give both a default constructor and a constructor that contains a detailed message. (The toString method of the Throwable superclass prints that detailed message, which is handy for debugging.)

java.lang.Throwable 1.0

  • Throwable()
    constructs a new Throwable object with no detailed message.
  • Throwable(String message)
    constructs a new Throwable object with the specified detailed message. By convention, all derived exception classes support both a default constructor and a constructor with a detailed message.
  • String getMessage()
    gets the detailed message of the Throwable object.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status

Core Java Topics