Sunday, March 22, 2009

DEALING WITH EXCEPTIONS IN JAVA


JAVA EXCEPTIONS
In JAVA, chances are that your program quit and spewed a bunch of mysterious errors to the screen. Those mysterious errors are exceptions. When your program quits, it's because an exception was "thrown." Exceptions can be thrown by the system or thrown by you, and they can be caught as well (catching an exception involves dealing with it so your program doesn't crash. You'll learn more about this later). "An exception was thrown" is the proper JAVA terminology for "an error happened."
Exceptions don't occur, they are thrown. JAVA throws an exception in response to an unusual situation. You can also throw your own exceptions, or catch an exception to gracefully manage errors.
In JAVA an Exception can be defined as "An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions".
The heart of the JAVA exception system is the exception itself. Exceptions in JAVA are actual objects, instances of classes that inherit from the class Throwable. When an exception is thrown, an instance of a Throwable class is created.

Throwable has two subclasses: Error and Exception. Instances of Error are internal errors in the JAVA runtime environment (the virtual machine). These errors are rare and usually fatal; there's not much you can do about them (either to catch them or to throw them yourself), but they exist so that JAVA can use them if it needs to.
The class Exception is more interesting. Subclasses of Exception fall into two general groups:
· Runtime exceptions (subclasses of the class RuntimeException) such as ArrayIndexOutofBounds, SecurityException, or NullPointerException.
· Other exceptions such as EOFException and MalformedURLException.
Runtime exceptions usually occur because of code that isn't very robust. An ArrayIndexOutofBounds exception, for example, should never be thrown if you're properly checking to make sure your code doesn't extend past the end of an array. NullPointerException exceptions won't happen if you don't try to reference the values of a variable that doesn't actually hold an object. If your program is causing runtime exceptions under any circumstances whatsoever, you should be fixing those problems before you even begin to deal with exception management.
The final group of exceptions is the most interesting because these are the exceptions that indicate that something very strange and out of control is happening. EOFExceptions, for example, happen when you're reading from a file and the file ends before you expect it to. MalformedURLExceptions happen when a URL isn't in the right format (perhaps your user typed it wrong). This group includes exceptions that you yourself create to signal unusual cases that may occur in your own programs.
Exceptions are arranged in a hierarchy like other classes, where the Exception superclasses are more general errors, and subclasses are more specific errors. This organization will become more important to you as you deal with exceptions in your own code.
Most of the exception classes are part of the java.lang package (including Throwable, Exception, and RuntimeException). But many of the other packages define other exceptions, and those exceptions are used throughout the class library. For example, the java.io package defines a general exception class called IOException, which is subclassed not only in the java.io package for input and output exceptions (EOFException, FileNotFoundException), but also in the java.net classes for networking exceptions such as MalFormedURLException.

Managing Exceptions In JAVA.
In many cases, the JAVA compiler enforces exception management when you try to use methods that use exceptions; you'll need to deal with those exceptions in your own code or it simply won't compile. In this section you'll learn about that consistency checking and how to use the try, catch, and finally language keywords to deal with exceptions that may or may not occur.
The JAVA compiler enforces exception management when you try to use methods that use exceptions; you'll need to deal with those exceptions in your own code or it simply won't compile. In this section you'll learn about that consistency checking and how to use the try, catch, and finally language keywords to deal with exceptions that may or may not occur.
Exception Consistency Checking
The more you work with the JAVA class libraries, the more likely it is that you'll run into a compiler error (an exception!) similar to this one:
TestProg.java
Exception java.lang.InterruptedException
must be caught or it must be declared in the throws clause
of this method.
What on earth does that mean? In JAVA, a method can indicate the kinds of errors it might possibly throw. For example, methods that read from files might potentially throw IOException errors, so those methods are declared with a special modifier that indicates potential errors. When you use those methods in your own JAVA programs, you have to protect your code against those exceptions. This rule is enforced by the compiler itself, the same way that the compiler checks to make sure that you're using methods with the right number of arguments and that all your variable types match the thing you're assigning to them.
Why is this check in place? By having methods declare the exceptions they throw, and by forcing you to handle those exceptions in some way, the potential for fatal errors in a program occurring because you simply didn't know they could occur is minimized. You no longer have to carefully read the documentation or the code of an object you're going to use to make sure you've dealt with all the potential problems-JAVA does the checking for you. And, on the other side, if you define your methods so that they indicate the exceptions they can throw, then JAVA can tell users of your objects to handle those errors.
Protecting Code and Catching Exceptions
Let's assume that you've been happily coding and during a test compile you ran into that exception message. According to the message, you have to either catch the error or declare that your method throws it. Let's deal with the first case: catching potential exceptions.
To catch an exception, you do two things:
· You protect the code that contains the method that might throw an exception inside a try block.
· You test for and deal with an exception inside a catch block.
What try and catch effectively mean is "try this bit of code that might cause an exception. If it executes okay, go on with the program. If it doesn't, catch the exception and deal with it."
For Example :
try { Thread.sleep(1000) }
catch (InterruptedException e) {}
While this example uses try and catch, it's not a very good use of it. Here, the Thread.sleep() class method could potentially throw an exception of type InterruptedException (for when the thread is interrupted from running). So we've put the call to sleep() inside the try clause to catch that exception if it happens. And inside catch (inside the parentheses), we indicate that we're specifically looking for InterruptedException exceptions. The problem here is that there isn't anything inside the catch clause-in other words, we'll catch the exception if it happens, but then we'll drop it on the floor and pretend we didn't see it. In all but the simplest cases (such as this one, where the exception really doesn't matter), you're going to want to put something inside the braces after catch to try to do something responsible to clean up after the exception happens.
The part of the catch clause inside the parentheses is similar to the parameter list of a method definition; it contains the class of the exception to be caught and a variable name (e is very commonly used). Inside the body of the catch clause, you can then refer to the exception object, for example, to get to the detailed error message contained in the getMessage() method:
catch (InterruptedException e) {
System.out.println("Ooops. Error: " + e.getMessage());
}
Here's another example. Say you have a program that reads from a file. This program most likely uses one of the streams classes . Stream and I/O," but the basic idea here is that you open a connection to a file and then use the read() method to get data from it. What if some strange disk error happens and the read() method can't read anything? What if the file is truncated and has fewer bytes in it than you expected? In either of these instances, the read() method will throw an IOException which, if you didn't catch it, would cause your program to stop executing and possibly crash. By putting your read() method inside a try clause, you can then deal gracefully with that error inside catch to clean up after the error and return to some safe state, to patch things up enough to be able to proceed, or, if all else fails, to save as much of the current program's state as possible and to exit. This example does just that; it tries to read from the file, and catches exceptions if they happen:
try {
while (numbytes <= mybuffer.length) {
myinputstream.read(mybuffer);
numbytes;++
}
} catch (IOException e) {
System.out.println("Ooops, IO Exception. Only read " + numbytes.");
// other cleanup code
}
Here, the "other cleanup code" can be anything you want it to be; perhaps you can go on with the program using the partial information you got from the file, or perhaps you want to put up a dialog saying that the file is corrupt and to let the user try to select another file or do some other operation.
Note that because the Exception classes are organized into hierarchies as other classes are, and because of the rule that you can use a subclass anywhere a superclass is expected, you can catch "groups" of exceptions and handle them with the same catch code. For example, although there are several different types of IOExceptions (EOFException, FileNotFoundException, and so on-see the java.io package for examples), by catching IOException you also catch instances of any subclass of IOException.
What if you do want to catch very different kinds of exceptions that aren't related by inheritance? You can use multiple catch clauses for a given try, like this:
try {
// protected code
} catch (OneKindOfException e) {
...
} catch (AnotherKindOfException e2) {
....
} catch (YetAnotherException e3) {
...
} catch (StilMoreException e4) {
....
}
Note that because the scope of local variables inside catch is the same as the scope of the outer block (the method definition or a loop if you're inside one), you'll have to use different local variables for each individual catch.
Because the first catch clause that matches is executed, you can build chains such as the following:
try {
someReallyExceptionalMethod();
} catch (NullPointerException n) { // a subclass of RuntimeException
. . .
} catch (RuntimeException r) { // a subclass of Exception
. . .
} catch (IOException i) { // a subclass of Exception
. . .
} catch (MyFirstException m) { // our subclass of Exception
. . .
} catch (Exception e) { // a subclass of Throwable
. . .
} catch (Throwable t) {
. . . // Errors, plus anything not caught above are caught here
}
By listing subclasses before their parent classes, the parent catches anything it would normally catch that's also not one of the subclasses above it. By juggling chains like these, you can express almost any combination of tests.
The finally Clause
Suppose there is some action in your code that you absolutely must do, no matter what happens, whether an exception is thrown or not. Usually, this is to free some external resource after acquiring it, to close a file after opening it, or something similar. While you could put that action both inside a catch and outside it, that would be duplicating the same code in two different places. Instead, put one copy of that code inside a special optional part of the try...catch clause, called finally:
SomeFileClass f = new SomeFileClass();
if (f.open("/a/file/name/path")) {
try {
someReallyExceptionalMethod();
{ catch (IOException e) {
// deal with errors
} finally {
f.close();
}
}
The finally clause is actually useful outside exceptions; you can also use it to execute cleanup code after a return, a break, or a continue inside loops. For the latter cases, you can use a try clause with a finally but without a catch clause.
Here's a fairly complex example of how this might work:
int mysteriousState = getContext();
while (true) {
System.out.print("Who ");
try {
System.out.print("is ");
if (mysteriousState == 1)
return;
System.out.print("that ");
if (mysteriousState == 2)
break;
System.out.print("strange ");
if (mysteriousState == 3)
continue;
System.out.print("but kindly ");
if (mysteriousState == 4)
throw new UncaughtException();
System.out.print("not at all ");
} finally {
System.out.print("amusing man?\n");
}
System.out.print("I'd like to meet the man");
}
System.out.print("Please tell me.\n");
Here is the output produced depending on the value of mysteriousState:
1 Who is amusing man? Please tell me.
2 Who is that amusing man? Please tell me.
3 Who is that strange amusing man? Who is that strange ....
4 Who is that strange but kindly amusing man? Please tell me.
5 Who is that strange but kindly not at all amusing man?
I'd like to meet that man. Who is that strange ...
Note
In cases 3 and 5, the output never ends until you quit the program. In 4, an error message generated by the UncaughtException is also printed.
Declaring Methods That Might Throw Exceptions
In the previous example you learned how to deal with methods that might possibly throw exceptions by protecting code and catching any exceptions that occur. The JAVA compiler will check to make sure you've somehow dealt with a method's exceptions-but how did it know which exceptions to tell you about in the first place?
The answer is that the original method indicated in its signature the exceptions that it might possibly throw. You can use this mechanism in your own methods-in fact, it's good style to do so to make sure that other users of your classes are alerted to the errors your methods may come across.
To indicate that a method may possibly throw an exception, you use a special clause in the method definition called throws.
The throws Clause
To indicate that some code in the body of your method may throw an exception, simply add the throws keyword after the signature for the method (before the opening brace) with the name or names of the exception that your method throws:
public boolean myMethod (int x, int y) throws AnException {
...
}
If your method may possibly throw multiple kinds of exceptions, you can put all of them in the throws clause, separated by commas:
public boolean myOtherMethod (int x, int y)
throws AnException, AnotherExeption, AThirdException {
...
}
Note that as with catch you can use a superclass of a group of exceptions to indicate that your method may throw any subclass of that exception:
public void YetAnotherMethod() throws IOException {
...
}
Keep in mind that adding a throws method to your method definition simply means that the method might throw an exception if something goes wrong, not that it actually will. The throws clause simply provides extra information to your method definition about potential exceptions and allows JAVA to make sure that your method is being used correctly by other people.
Think of a method's overall description as a contract between the designer of that method (or class) and the caller of the method (you can be either side of that contract, of course). Usually, the description indicates the types of a method's arguments, what it returns, and the general semantics of what it normally does. Using throws, you add information about the abnormal things it can do as well. This new part of the contract helps to separate and make explicit all the places where exceptional conditions should be handled in your program, and that makes large-scale design easier.
Which Exceptions Should You Throw?
Once you decide to declare that your method might throw an exception, you have to decide which exceptions it might throw (and actually throw them or call a method that will throw them-you'll learn about throwing your own exceptions in the next section). In many instances, this will be apparent from the operation of the method itself. Perhaps you're creating and throwing your own exceptions, in which case you'll know exactly which exceptions to throw.
You don't really have to list all the possible exceptions that your method could throw; some exceptions are handled by the runtime itself and are so common (well, not common, but ubiquitous) that you don't have to deal with them. In particular, exceptions of either class Error or RuntimeException (or any of their subclasses) do not have to be listed in your throws clause. They get special treatment because they can occur anywhere within a JAVA program and are usually conditions that you, as the programmer, did not directly cause. One good example is OutOfMemoryError, which can happen anywhere, at any time, and for any number of reasons. These two kinds of exceptions are called implicit exceptions, and you don't have to worry about them.
Implicit exceptions are exceptions that are subclasses of the classes RuntimeException and Error. Implicit exceptions are usually thrown by the JAVA runtime itself. You do not have to declare that your method throws them.
Note
You can, of course, choose to list these errors and runtime exceptions in your throws clause if you like, but the callers of your methods will not be forced to handle them; only non-runtime exceptions must be handled.
All other exceptions are called explicit exceptions and are potential candidates of a throws clause in your method.
Passing On Exceptions
In addition to declaring methods that throw exceptions, there's one other instance in which your method definition may include a throws clause. In this case, you want to use a method that throws an exception, but you don't want to catch that exception or deal with it. In many cases, it might make more sense for the method that calls your method to deal with that exception rather than for you to deal with it. There's nothing wrong with this; it's a fairly common occurrence that you won't actually deal with an exception, but will pass it back to the method that calls yours. At any rate, it's a better idea to pass on exceptions to calling methods than to catch them and ignore them.
Rather than using the try and catch clauses in the body of your method, you can declare your method with a throws clause such that it, too, might possibly throw the appropriate exception. Then it's the responsibility of the method that calls your method to deal with that exception. This is the other case that will satisfy the JAVA compiler that you have done something with a given method. Here's another way of implementing an example that reads characters from a stream:
public void readTheFile(String filename) throws IO Exception {
// open the file, init the stream, etc.
while (numbytes <= mybuffer.length) {
myinputstream.read(mybuffer);
numbytes;++
}
This example is similar to the example used previously today; remember that the read() method was declared to throw an IOException, so you had to use try and catch to use it. Once you declare your method to throw an exception, however, you can use other methods that also throw those exceptions inside the body of this method, without needing to protect the code or catch the exception.
Note
You can, of course, deal with other exceptions using try and catch in the body of your method in addition to passing on the exceptions you listed in the throws clause. You can also both deal with the exception in some way and then re-throw it so that your method's calling method has to deal with it anyhow. You'll learn how to throw methods in the next section.
throws and Inheritance
If your method definition overrides a method in a superclass that includes a throws clause, there are special rules for how your overridden method deals with throws. Unlike with the other parts of the method signature, your new method does not have to have the same set of exceptions listed in the throws clause. Because there's a potential that your new method may deal better with exceptions, rather than just throwing them, your subclass's method can potentially throw fewer types of exceptions than its superclass's method definition, up to and including throwing no exceptions at all. That means that you can have the following two class definitions and things will work just fine:
public class Fruit {
public void ripen() throws RotException {
...
}
}
public class WaxFruit extends Fruit {
public void ripen() {
...
}
}
The converse of this rule is not true; a subclass's method cannot throw more exceptions (either exceptions of different types or more general exception classes) than its superclass's method.

No comments:

Post a Comment

Thanks for your opinion....