Sunday 12 March 2017

Java’s Built-in Exceptions, Creating Your Own Exception Subclasses, Chained Exceptions & Using Exceptions - Java Tutorials

Java’s Built-in Exceptions

Inside the standard package java.lang, Java defines several exception classes. A few have been used by the preceding examples. The most general of these exceptions are subclasses of the standard type RuntimeException. Since java.lang is implicitly imported into all Java programs, most exceptions derived from RuntimeException are automatically available. Furthermore, they need not be included in any method’s throws list. In the language of Java, these are called unchecked exceptions because the compiler does not check to see if a method handles or throws these exceptions. The unchecked exceptions defined in java.lang are listed in Table 10-1. Table 10-2 lists those exceptions defined by java.lang that must be included in a method’s throws list if that method can generate one of these exceptions and does not handle it itself. These are called checked exceptions. Java defines several other types of exceptions that relate to its various class libraries.


Java’s Unchecked RuntimeException Subclasses

Exception                                                Meaning

ArithmeticException                               Arithmetic error, such as divide-by-zero.

ArrayIndexOutOfBoundsException        Array index is out-of-bounds.

ArrayStoreException                               Assignment to an array element of an incompatible type.

ClassCastException                                 Invalid cast.

IllegalArgumentException                      Illegal argument used to invoke a method.

IllegalMonitorStateException                 Illegal monitor operation, such as waiting on an 
                                                                 unlocked thread.

IllegalStateException                               Environment or application is in incorrect state.

IllegalThreadStateException                   Requested operation not compatible with current 
                                                                 thread state.

IndexOutOfBoundsException                 Some type of index is out-of-bounds.

NegativeArraySizeException                  Array created with a negative size.

NullPointerException                              Invalid use of a null reference.

NumberFormatException                        Invalid conversion of a string to a numeric format.

SecurityException                                    Attempt to violate security.

StringIndexOutOfBounds                        Attempt to index outside the bounds of a string.

UnsupportedOperationException            An unsupported operation was encountered.


Java’s Checked Exceptions Defined in java.lang

Exception                                                Meaning

ClassNotFoundException                        Class not found.

CloneNotSupportedException                 Attempt to clone an object that does not implement the
                                                                 Cloneable interface.

IllegalAccessException                            Access to a class is denied.

InstantiationException                              Attempt to create an object of an abstract class or interface.

InterruptedException                                One thread has been interrupted by another thread.

NoSuchFieldException                             A requested field does not exist.

NoSuchMethodException                         A requested method does not exist.




Creating Your Own Exception Subclasses

Although Java’s built-in exceptions handle most common errors, you will probably want to create your own exception types to handle situations specific to your applications. This is quite easy to do: just define a subclass of Exception (which is, of course, a subclass of Throwable). Your subclasses don’t need to actually implement anything—it is their existence in the type system that allows you to use them as exceptions.

The Exception class does not define any methods of its own. It does, of course, inherit those methods provided by Throwable. Thus, all exceptions, including those that you create, have the methods defined by Throwable available to them. They are shown in Table 10-3. Notice that several methods were added by Java 2, version 1.4. You may also wish to override one or more of these methods in exception classes that you create.


The Methods Defined by Throwable

Method                                                    Description

Throwable fillInStackTrace( )                  Returns a Throwable object that contains a completed 
                                                                  stack trace. This object can be rethrown.

Throwable getCause( )                             Returns the exception that underlies the current exception. 
                                                                  If there is no underlying exception, null is returned. Added 
                                                                  by Java 2, version 1.4.

String getLocalizedMessage( )                 Returns a localized description of the exception.

String getMessage( )                                 Returns a description of the exception.

StackTraceElement[ ] getStackTrace( )    Returns an array that contains the stack trace, one element 
                                                                   at a time as an array of StackTraceElement. The method 
                                                                   at the top of the stack is the last method called before the 
                                                                   exception was thrown. This method is found in the first 
                                                                   element of the array. The StackTraceElement class gives 
                                                                   your program access to information about each element in 
                                                                   the trace, such as its method name. Added by 
                                                                   Java 2, version 1.4

Throwable initCause(Throwable               Associates causeExc with the invoking exception as 
                                   causeExc)                a cause of the invoking exception. Returns a reference 
                                                                   to the exception. Added by Java 2, version 1.4
                      
void printStackTrace( )                              Displays the stack trace.

void printStackTrace(PrintStream             Sends the stack trace to the specified stream.
                                   stream)

void printStackTrace(PrintWriter              Sends the stack trace to the specified stream.
stream)

void setStackTrace(StackTraceElement    Sets the stack trace to the elements passed in elements.                                         elements[ ])                This method is for specialized applications, not normal 
                                                                    use. Added by Java 2, version 1.4


String toString( )                                        Returns a String object containing a description of 
                                                                    the exception. This method is called by println( ) 
                                                                    when outputting a Throwable object.


The following example declares a new subclass of Exception and then uses that subclass to signal an error condition in a method. It overrides the toString( ) method, allowing the description of the exception to be displayed using println( ).

  // This program creates a custom exception type.
  class MyException extends Exception {
    private int detail;

    MyException(int a) {
      detail = a;
    }

    public String toString() {
      return "MyException[" + detail + "]";
    }
  }

  class ExceptionDemo {
    static void compute(int a) throws MyException {
      System.out.println("Called compute(" + a + ")");
      if(a > 10)
        throw new MyException(a);
      System.out.println("Normal exit");
    }

    public static void main(String args[]) {
      try {
        compute(1);
        compute(20);
      } catch (MyException e) {
        System.out.println("Caught " + e);
      }
    }
  }

This example defines a subclass of Exception called MyException. This subclass is quite simple: it has only a constructor plus an overloaded toString( ) method that displays the value of the exception. The ExceptionDemo class defines a method named compute( ) that throws a MyException object. The exception is thrown when compute( )’s integer parameter is greater than 10. The main( ) method sets up an exception handler for MyException, then calls compute( ) with a legal value (less than 10) and an illegal one to show both paths through the code. Here is the result:

  Called compute(1)
  Normal exit
  Called compute(20)
  Caught MyException[20]




Chained Exceptions

Java 2, version 1.4 added a new feature to the exception subsystem: chained exceptions. The chained exception feature allows you to associate another exception with an exception. This second exception describes the cause of the first exception. For example, imagine a situation in which a method throws an ArithmeticException because of an attempt to divide by zero. However, the actual cause of the problem was that an I/O error occurred, which caused the divisor to be set improperly. Although the method must certainly throw an ArithmeticException, since that is the error that occurred, you might also want to let the calling code know that the underlying cause was an I/O error. Chained exceptions let you handle this, and any other situation in which layers of exceptions exist.

To allow chained exceptions, Java 2, version 1.4 added two constructors and two methods to Throwable. The constructors are shown here.

  Throwable(Throwable causeExc)
  Throwable(String msg, Throwable causeExc)

In the first form, causeExc is the exception that causes the current exception. That is, causeExc is the underlying reason that an exception occurred. The second form allows you to specify a description at the same time that you specify a cause exception. These two constructors have also been added to the Error, Exception, and RuntimeException classes.

The chained exception methods added to Throwable are getCause( ) and initCause( ). These methods are shown in Table 10-3, and are repeated here for the sake of discussion.

  Throwable getCause( )
  Throwable initCause(Throwable causeExc)

The getCause( ) method returns the exception that underlies the current exception. If there is no underlying exception, null is returned. The initCause( ) method associates causeExc with the invoking exception and returns a reference to the exception. Thus, you can associate a cause with an exception after the exception has been created. However, the cause exception can be set only once. Thus, you can call initCause( ) only once for each exception object. Furthermore, if the cause exception was set by a constructor, then you can’t set it again using initCause( ).

In general, initCause( ) is used to set a cause for legacy exception classes which don’t support the two additional constructors described earlier. At the time of this writing, most of Java’s built-in exceptions, such as ArithmeticException, do not define the additional constructors. Thus, you will use initCause( ) if you need to add an exception chain to these exceptions. When creating your own exception classes you will want to add the two chained-exception constructors if you will be using your exceptions in situations in which layered exceptions are possible.

Here is an example that illustrates the mechanics of handling chained exceptions.

  // Demonstrate exception chaining.
  class ChainExcDemo {
    static void demoproc() {
      // create an exception
      NullPointerException e =
        new NullPointerException("top layer");

      // add a cause
      e.initCause(new ArithmeticException("cause"));

      throw e;
    }

    public static void main(String args[]) {
      try {
        demoproc();
      } catch(NullPointerException e) {
        // display top level exception
        System.out.println("Caught: " + e);

        // display cause exception
        System.out.println("Original cause: " + e.getCause());
      }
    }
  }

The output from the program is shown here.

  Caught: java.lang.NullPointerException: top layer
  Original cause: java.lang.ArithmeticException: cause

In this example, the top-level exception is NullPointerException. To it is added a cause exception, ArithmeticException. When the exception is thrown out of demoproc( ), it is caught by main( ). There, the top-level exception is displayed, followed by the underlying exception, which is obtained by calling getCause( ).

Chained exceptions can be carried on to whatever depth is necessary. Thus, the cause exception can, itself, have a cause. Be aware that overly long chains of exceptions may indicate poor design.

Chained exceptions are not something that every program will need. However, in cases in which knowledge of an underlying cause is useful, they offer an elegant solution.




Using Exceptions

Exception handling provides a powerful mechanism for controlling complex programs that have many dynamic run-time characteristics. It is important to think of try, throw, and catch as clean ways to handle errors and unusual boundary conditions in your program’s logic. If you are like most programmers, then you probably are used to returning an error code when a method fails. When you are programming in Java, you should break this habit. When a method can fail, have it throw an exception. This is a cleaner way to handle failure modes.

One last point: Java’s exception-handling statements should not be considered a general mechanism for nonlocal branching. If you do so, it will only confuse your code and make it hard to maintain.

No comments:

Post a Comment