JAVA.ZTOR.COM :: Fundamental Topics
Exceptions are the vital important mechanism in java programming. Handling errors in your programs has direct impact on whether your application run or not. It direct affects on all aspects of developing software. Exceptions allow to separate error-handling code from regular code, it is make your code more clear and easy to maintain.

Checked and Unchecked Exceptions

There are two kinds of exceptions in Java: checked and unchecked exceptions. All checked exceptions are verified by compiler. You must handle exception of this type in method or you must declare that your method throws exception. There are two super-class of unchecked exceptions: RuntimeException and Error. Diagram below depicts exception classes hierarchy.

Handling Exceptions

You can handle exception otherwise you must declare it. Also you can handle some exceptions and declare others.

Handle ExceptionsDeclare Exceptions
public void myMethod() {
try {
  . . .
}
catch (ExceptionType1 e) {
  . . .
}
catch (ExceptionType2 e) {
  . . .
}
finally {
  . . .
}
public void myMethod() throws ExceptionType1,ExceptionType2 {
  . . .
}

Example:

public Integer[] readIntegersFromFile(String p_filename)
        throws FileNotFoundException, IOException {
        
    BufferedReader in = null;
    Integer[] ret_data = null;
    
    if (p_filename == null) {
        throw new IllegalArgumentException("File name is null");
    }
    
    try {

        in = new BufferedReader(new InputStreamReader(new FileInputStream(
                p_filename)));

        ArrayList<Integer> ret_res = new ArrayList<Integer>();
        String x_str;
        int x_linenumber = 0;
    
        while ((x_str = in.readLine()) != null) {
            try {
                x_linenumber++;
                ret_res.add(new Integer(x_str));
            } catch (NumberFormatException e) {
                System.err.println("Invalid data in file: " + p_filename
                        + "; Line number: " + x_linenumber + " Data: " + x_str);
            }
        }

        ret_data = new Integer[ret_res.size()];
        return (Integer[]) ret_res.toArray(ret_data);
    
    } finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (IOException e) {
            System.err.println("Error in finally block " + e);
        }
    }
}


Comments:
• Lines with invalid data in source file are ignored, we just register it.
• Declaration of IllegalArgumentException can be omitted, because it belongs to RuntmeException.
• FileNotFoundException, IOException are propagated to the caller, because it can make more appropriated decision for these cases.

Creating your own exception classes

Before creating your own exception you must double check existing exceptions in Java API. If you can find what you need, use standard exception.

If you have decided to create your own exception, keep following rules:
• Choose a superclass from exception classes hierarchy which most close to yours and extend it.
• Avoid to extend Error and RuntimeException.
• Good practice to append the word "Exception" to the end of your class.


Example:

public class ObjectLockedException extends Exception {
    
    private String o_holder = null;

    public ObjectLockedException(String p_message, String p_holder) {
        super(p_message);
        o_holder = p_holder;
    }
    
    public ObjectLockedException(String p_message, String p_holder, Throwable p_exception) {
        super(p_message,p_exception);
        o_holder = p_holder;        
    }
    
    public String getObjectHolder() {
        return o_holder;
    }
    
}

Throwable class, getStackTrace, initCause, getCause

Class Throwable is the main super-class for all exceptions. It has:

Constructors

Throwable()
Throwable(String message)
Throwable(String message, Throwable cause)
Throwable(Throwable cause)

Methods

ThrowablefillInStackTrace()
ThrowablegetCause()
StringgetLocalizedMessage()
StringgetMessage()
StackTraceElement[]getStackTrace()
ThrowableinitCause(Throwable cause)
voidprintStackTrace()
voidprintStackTrace(PrintStream s)
voidprintStackTrace(PrintWriter s)
voidsetStackTrace(StackTraceElement[] stackTrace)
StringtoString()

getStackTrace

Provides programmatic access to the stack trace information printed by printStackTrace().
It returns array of StackTraceElement objects. Class StackTraceElement contains methods:
getClassName(), getFileName(), getLineNumber(), getMethodName() .
WARNINGS:
• Some virtual machines may omit one or more stack frames from the stack trace.
• File and line number information may not exist under JIT compilers and dynamic, optimizing compilers (like Sun Microsystems'HotSpot).

initCause

Initializes the cause of this throwable to the specified value. (The cause is the throwable that caused this throwable to get thrown.) You can use specific constructor instead of using this method. This method can be called at most once, as rule immediately after creating the throwable.

getCause

Method retrieves cause of exception. A null value is permitted, and indicates that the cause is nonexistent or unknown.

Best Practices in Exception Handling

• In the catch block log exception or throw other exception, never do both.

• Declare and catch the specific checked exceptions. Try to avoid following styles:
    public void foo() throws Exception {
    and
    catch (Exception e) {

• If your method can throw many exceptions, that basically mean the same thing to the caller, wrap them in a single checked exception:
    public void foo() throws MyException1,MyException2,...,MyExceptionN {
    if they have the same super class, change you code to:
    public void foo() throws MySuperException {
    else - you can create new exception MyGroupException and throw it with different causes:
    public void foo() throws MyGroupException {
    . . .
    catch (MyException1 e) {
       throw new MyGroupException(e);
    }
    . . .
    catch (MyExceptionN e) {
       throw new MyGroupException(e);
    }


• If you return null in catch block, you are losing the information forever. Try to never return null (not only in catch block), throwing appropriated exceptions make your code more robust and controlled.

• Don't ignore InterruptedException. In many cases it inform you to stop it's doing.