Exceptions

Exceptions are a general way of handling errors. When an error occurs in the system or our code generates one, an exception object is created. It holds the details about the problem. The Java runtime system has a large number of these to represent a the kinds of errors that can happen when a program runs. Things like divide by 0, or an attempt to run a method that doesn't exist, references to an object that doesn't exist, out of memory, etc. You can create your own exception classes to represent problems that are unique to your application.

When an exception occurs, there are several general ways to handle them.

If option 1 is chosen, you get an error message that tries to explain the error, followed by a stack trace. A stack trace is a list of the methods that were called leading to the current one. They are displayed in reverse chronological order, with the most recent method first.

Here is a simple example. It calls a couple of methods, then tries to divide 1 by 0.


public class stktrace
{
    public static void method1() { method2(); }
    public static void method2() 
    { 
        System.out.println("method2"); 
        int a = 1/0;
    } // method2

    public static void main(String[] args)
    {
        System.out.println("Calling the first method");
        method1();
        System.out.println("Done calling the first method");
    } // main
} // class stktrace

Calling the first method
method2
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at stktrace.method2(stktrace.java:7)
    at stktrace.method1(stktrace.java:3)
    at stktrace.main(stktrace.java:13)
The line starting with the word "Exception" contains the error message. The other lines are the stack trace. the first "at" line shows that the error occurred in method2() at line 7 of the file. The next line shows that method2() was called from method1() at line 3 and finally, method1() got called from main() at line 13. Also note that the print statement after the call to method1() in main() never got executed. Once the exception occurred, all other processing stopped.

Now, let's handle the exception. In this case, there is very little we can actually do but we can print a more meaningful message and exit nicely.


public class stktrace
{
    public static void method1() { method2(); }
    public static void method2() 
    { 
        System.out.println("method2"); 
        int a = 1/0;
    } // method2

    public static void main(String[] args)
    {
        System.out.println("Calling the first method");
        try {
            method1();
        }
        catch(ArithmeticException a) {
            System.out.println("Arithmetic problem, stopping");
            System.out.println("System message was '"+ a.getMessage() + "'");
            System.out.println("and here is how we got here");
            a.printStackTrace();
            System.exit(1);
        } // catch
        System.out.println("Done calling the first method");
    } // main
} // class stktrace

Calling the first method
method2
Arithmetic problem, stopping
System message was '/ by zero'
and here is how we got here
java.lang.ArithmeticException: / by zero
    at stktrace.method2(stktrace.java:7)
    at stktrace.method1(stktrace.java:3)
    at stktrace.main(stktrace.java:14)

Exception Odds and Ends

You can add a special clause to the list of catch clauses. You can have a finally clause. The code in this section is executed when the try block is complete. This is either after it completes successfully or after the catch is executed.

Exceptions can be handled locally, as in the examples above. Or they can be passed on to a higher level. This code, from the examples (Listing 8.3-4) show how this can be done.


//********************************************************************
//  Propagation.java       Author: Lewis and Loftus
//
//  Demonstrates exception propagation.
//********************************************************************

public class Propagation
{
   //-----------------------------------------------------------------
   //  Invokes the level1 method to begin the exception demonstration.
   //-----------------------------------------------------------------
   static public void main (String[] args)
   {
      ExceptionScope demo = new ExceptionScope();

      System.out.println("Program beginning.");
      demo.level1();
      System.out.println("Program ending.");
   }
}
//********************************************************************
//  ExceptionScope.java       Author: Lewis and Loftus
//
//  Demonstrates exception propagation.
//********************************************************************

public class ExceptionScope
{
   //-----------------------------------------------------------------
   //  Catches and handles the exception that is thrown in level3.
   //-----------------------------------------------------------------
   public void level1()
   {
      System.out.println("Level 1 beginning.");

      try
      {
         level2();
      }
      catch (ArithmeticException problem)
      {
         System.out.println ();
         System.out.println ("The exception message is: " +
                             problem.getMessage());
         System.out.println ();
         System.out.println ("The call stack trace:");
         problem.printStackTrace();
         System.out.println ();
      }

      System.out.println("Level 1 ending.");
   }

   //-----------------------------------------------------------------
   //  Serves as an intermediate level.  The exception propagates
   //  through this method back to level1.
   //-----------------------------------------------------------------
   public void level2()
   {
      System.out.println("Level 2 beginning.");
      level3 ();
      System.out.println("Level 2 ending.");
   }

   //-----------------------------------------------------------------
   //  Performs a calculation to produce an exception.  It is not
   //  caught and handled at this level.
   //-----------------------------------------------------------------
   public void level3 ()
   {
      int numerator = 10, denominator = 0;

      System.out.println("Level 3 beginning.");
      int result = numerator / denominator;
      System.out.println("Level 3 ending.");
   }
}
There is an exception hierarchy, like there is a class hierarchy. Some of the entries can be seem on page 387. You can create your own exception by creating classes that extend the Exception class.

// this is our exception. We use the parent classes
// constructor method. Then we print our message.
public class baddivision extends Exception
{
	baddivision(String message) { 
			super(message); 
			System.out.println("Division problem, stopping");
	}
} // badDivision
This class does the arithmetic and causes and catches the exception.

// this performs a division operation on the arguments.
// It catches the builtin exception and throws its own.
public class helper
{
	public int method1(int numer,int denom) throws baddivision
	{ 
		System.out.println("method1"); 
		try {
			return numer/denom;
		}
		catch(ArithmeticException a) {
			throw new baddivision("can't divide " + numer + " by " + denom);
		} // catch
	} // method1
} // class helper
Then the main class that tests the others.

// this is the test code for the exception example
public class exc1
{
	public static void main(String[] args)
	{
		int c=-1;
		System.out.println("Calling the method with args that should work");
		helper h = new helper();
		try {
			c = h.method1(10,3);
		}
		catch(baddivision b) {
			System.out.println("System message was '"+ b.getMessage() + "'");
			System.exit(1);
		} // catch
		System.out.println("c = " + c);
		System.out.println("Done calling the method with args that should work");

		System.out.println("Calling the method with args that should fail");
		try {
			c = h.method1(10,0); // this will divide by 0
		}
		catch(baddivision b) {
			System.out.println("System message was '"+ b.getMessage() + "'");
			System.exit(1);
		} // catch
		// we should never see these messages
		System.out.println("c = " + c);
		System.out.println("Done calling the method with args that should fail");
	} // main
} // class exc1
The output looks like this.

Calling the method with args that should work
method2
c = 3
Done calling the method with args that should work
Calling the method with args that should fail
method2
Division problem, stopping
System message was 'can't divide 10 by 0'
This code can also be found here. Note the definition of method1() has a throws clause at the end. This lists the exceptions that this method may throw. The compiler will tell you if you need one and don't have it.