CSC448: Exceptions: Introduction [6/12] Previous pageContentsNext page

The traditional solution to dealing with exceptional cases is to distinguish normal values from exceptional values, and to require every piece of code to check for exceptional values. However, this is neither robust nor manageable, even in modestly sized systems, nor is it appropriate for processing asynchronous errors.

Exceptions provide a control-flow mechanism that is quite different from other control-flow constructs found in common languages.

Exceptions provide a form of non-local jump where the destination is unknown: we must provide an exception name and the runtime system will jump to the most recent exception handler block that we are currently inside.

In addition, the runtime system may:

Some examples:

file:E1.java [source] [doc-public] [doc-private]
00001: class E1 extends Exception 
00002: {
00003:   E1 () {
00004:   }
00005: }
00006: 

file:E2.java [source] [doc-public] [doc-private]
00001: class E2 extends RuntimeException 
00002: {
00003:   E2 () {
00004:   }
00005: }
00006: 

Pass through many activation records and reach the top-level exception handler, as well as checked vs unchecked exceptions:

file:Test1.java [source] [doc-public] [doc-private]
00001: class Test1 
00002: {
00003:   public static void main (String[] args)
00004:     throws E1
00005:   {
00006:     int n = Integer.parseInt (args[0]);
00007:     foo (n);
00008:   }
00009:   
00010: 
00011:   static void foo (int n) 
00012:     throws E1
00013:   {
00014:     if (n == 0) {
00015:       throw new E1 ();
00016:     } else if (n == 1) {
00017:       throw new E2 ();
00018:     } else {
00019:       foo (n - 2);
00020:     }
00021:   }
00022: }
00023: 

More complex control flow:

file:Test2.java [source] [doc-public] [doc-private]
00001: import java.io.FileWriter;
00002: import java.io.IOException;
00003: import java.io.PrintWriter;
00004: 
00005: 
00006: class Test2
00007: {
00008:   public static void main (String[] args)
00009:   {
00010:     double failureProbability = Double.parseDouble (args[0]);
00011:     int numLines = 0;
00012: 
00013:     try {
00014:       FileWriter fw = new FileWriter ("output.txt");
00015: 
00016:       try {
00017:         for (; numLines < 30; numLines++) {
00018:           fw.write (generateLine (failureProbability) + "\n");
00019:           try {
00020:             Thread.sleep (50);
00021:           } catch (InterruptedException e) {
00022:             // Ignore InterruptedException.
00023:           }
00024:         }
00025:       } catch (E1 e) {
00026:         System.err.println ("Caught E1 exception from generateLine");
00027:       } catch (IOException e) {
00028:         System.err.println ("Unable to output to file");
00029:       } finally {
00030:         try {
00031:           fw.write ("Number of lines written: " + numLines + "\n");
00032:           fw.close ();
00033:         } catch (IOException e) {
00034:           System.err.println ("Unable to write summary entry and close file");
00035:         }
00036:       }
00037: 
00038:     } catch (IOException e) {
00039:       System.err.println ("Unable to open file");
00040:       e.printStackTrace ();
00041:     }
00042:   }
00043: 
00044: 
00045:   static String generateLine (double failureProbability)
00046:     throws E1
00047:   {
00048:     // Model failure with probability failureProbability.
00049:     if (Math.random () < failureProbability) {
00050:       throw new E1 ();
00051:     }
00052: 
00053:     return "Log entry [" + System.currentTimeMillis () + "ms]";
00054:   }
00055: }
00056: 

Finally blocks always executed:

file:Test3.java [source] [doc-public] [doc-private]
00001: class Test3
00002: {
00003:   public static void main (String[] args)
00004:     throws E1
00005:   {
00006:     try {
00007:       double failureProbability = Double.parseDouble (args[0]);
00008:       if (Math.random () < failureProbability) {
00009:         throw new E1 ();
00010:       }
00011:     } finally {
00012:       System.out.println ("Executed finally block");
00013:     }
00014:   }
00015: }
00016: 

Finally blocks always executed, even in odd situations:

file:Test4.java [source] [doc-public] [doc-private]
00001: class Test4
00002: {
00003:   public static void main (String[] args)
00004:     throws E1
00005:   {
00006:     for (int i = 0; i < 5; i++) {
00007:       if (true) {
00008:         continue;
00009:       }
00010:       System.out.println ("Executed first block");
00011:     }
00012: 
00013:     for (int i = 0; i < 5; i++) {
00014:       try {
00015:         continue;
00016:       } finally {
00017:         System.out.println ("Executed second block");
00018:       }
00019:     }
00020:   }
00021: }
00022: 

There are many tricky details:

Previous pageContentsNext page