CM10135 / Programming II:   Lecture 8


Errors, Exceptions & Other Strange Ways to Get Around


I. The Wee Note

  1. Errors & Exceptions are covered in your Blue J book in Chapter 11.

II. Nonlinear Control of Flow

  1. Somewhere, for any executing program, there is a special references that says what statement is about to be executed next.
  2. Programmers think best about sequences --- simple plans, always go to the next step.
  3. Loops are a little tricker to think about, because they make the pointer skip around (although in a very determined way.)
  4. In the beginning, before loops & subroutines, there was GOTO
    1. use a line number of the code
    2. more sophisticated, use a label
    3. Used to create iteration, subroutines.
    4. Assembly code is still like this.
  5. Example: 
    mysum = 0
    myiterator = 0
    LOOP:
    if myiterator == 5
    goto END
    mysum += myiterator
    myiterator += 1
    goto LOOP
    END:
    print "mysum = " mysum
  6. Once loops & function calls had been invented, non-linear control was considered inelegant / bad style.
    1. Generally, this is true.  People have more trouble reading code if it doesn't go in a sequence.
    2. Loops are self-documenting, they tend to tell you what their criteria & index are in the test.
    3. Function/method calls are also self-documenting, they are abstract & their names should tell you want they do.
    4. However, this has always been a little controversial.
    5. Sometimes making a loop do exactly what you want is just so messy that jumping out of it might be better.
    6. But in general, programmers who use GOTO use it because they haven't thought hard enough about the alternatives, so it is widely condemned.
    7. I am sure someone in this department will think I shouldn't even have mentioned the notion to you!
  7. Java has a number of ways of going non-linear
    1. break & continue,
      1. only work in loops
      2. will accept labels as arguments.
    2. return: can happen anywhere in a method call, skips the rest of the code.
    3. error/exception handling (today's main topic).
    4. thread handling (we'll do this tomorrow).
  8. Quickly, here's what break & continue do:
    1. break ends a loop & transfers the flow of control to whatever comes next.
    2. continue returns to the top of a loop, skipping any remaining code in the loop.
    3. Either command can take an argument
      1. lets you disambiguate which loop you want to break or continue if you are in nested loops.
      2. Labels are similar as above, you just stick a name in with a colon after it, but it must be right before a loop starts.
    4. Here's a page from Sun with some examples:

III. Signals & Errors

  1. One reason that you might want to go non-linear is if something else interrupted your program.  Examples:
    1. The machine is being shut down.
    2. Someone wants to chat to you (this is now usually handled by the OS/windowing system).
    3. You want the program to do something every five minutes (like save it's current state in a file on the hard disk.)
    4. Someone killed your window with a mouse.
  2. Don't want the program to just die exactly when the event occurs!
    1. Probably want to save state.
    2. Always want to:
      1. close files --- make sure disk is safe,
      2. kill children / spawned processes (e.g. dependent sub-windows, like "find").
    3. May want to go back to what you were doing after you've handled the situation.
  3. These problems can always happen, not controversial that you should be able to handle them.
  4. Common metaphor in many programming languages is catching & throwing.
    1. Something "throws" an exception when an event happens.
    2. Something else needs to catch it!

IV. Throwables

  1. In Java, things that can throw are subclasses of java.lang.Throwable
  2. Things that are Throwable are either Exceptions or Errors.
  3. Errors tend to be things you can't do much about, so people don't tend to check for them in the code
    1. Either things that come from outside that you can't fix, or things that are really sort of glorified syntax errors. 
    2. Examples:
      AbstractMethodError ClassCircularityError ClassFormatError IllegalAccessError IncompatibleClassChangeError InstantiationError InternalError NoClassDefFoundError NoSuchFieldError NoSuchMethodError OutOfMemoryError StackOverflowError ThreadDeath UnknownError UnsupportedClassVersionError VerifyError VirtualMachineError
    3. Show on laptop file:///home/joanna/s1studio_jdk/j2sdk1.4.1_02/docs/api/index.html
  4. Exceptions are things you might want to do something about.
  5. Exceptions come in two types:
    1. checked:  you are obligated to do something about them or the compiler won't let you compile.
    2. unchecked:  you can look for them if you like, it's up to you.
  6. What's the difference?
    1. Some kinds of bad things will happen for exogenous reasons the programmer can't control, but can anticipate.
      1. e.g. not being able to write to a disk --- could be full.
      2. These are checked exceptions.
    2. Some kinds of bad things will only happen if a programmer makes a mistake.
      1. e.g. asking for an illegal index for an array.
      2. These are unchecked exceptions.
  7. All unchecked exceptions are a subclass of RuntimeExceptions (which is a subclass of Exceptions.)
    1. Examples: ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException, ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFormatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException
  8. Arguable whether you should check for unchecked exceptions:
    1. Do you expect other programmers who don't read your comments carefully to use your code?
    2. Do you think you might make a mistake while you are programming?
    3. Do you think the user might make a mistake that might break your code?
    4. Often inserted during development / debugging, or based on personal experience.
  9. With checked exceptions,  you can actually get away with very little.
    1. The least you can do is to declare that the method throws the exception, thus passing the problem on to the next calling method.
    2. If nothing ever actually checks it, then when the exception gets triggered you will crash the virtual machine.
    3. The compiler makes sure you know this can happen (generally considered unprofessional to crash the VM.)
    4. More about this below.

V. Catching Throwables

  1. The actual catching (and throwing) is done in syntax, not with objects.
  2. Keywords:  try {} catch {}* finally {}.
  3. Any checked exception must be performed within a try clause.
  4. Any try clause must be followed by one or more catch clauses, each for a particular error.
    1. Order matters -- the first applicable catch phrase is applied.
    2. So you can finish with a very general one
    3. e.g. here's a piece of a program which is letting the user type an array index to access.  Whatever they typed in is in "myNumString", which is currently just a string.  This code tries to convert it into an integer.
      try {
      newIx = Integer.decode(myNumString).intValue();
      } catch (NumberFormatException nfe) {
      System.out.println("please only enter integers!");
      ewIx = 0; // give newIx some value that won't stop the program
      } catch (Exception ex) {
      System.out.println("Wow, I didn't expect a " + ex);
      ex.printStackTrace(); newIx = 0;
      }
    4. Exceptions and NumberFormatExceptions are both classes.
    5. nfe & ex are both objects!
    6. ex won't be instantiated if nfe is:  only one catch clause runs.
    7. Have a look at the Java Doc to see what you can do with these objects.
    8. Printing their stack trace is very useful, it tells you what the call history was.
    9. Other ways to handle exeptions:
      1. Stop everything: System.exit(1);  Generally considered bad form!
      2. Throw a new exception of a type of your own making (see below.)
  5. Finally clauses are optional, run after ALL the other clauses.
    1. Allows you to have something that happens regardless of whether any of the catches is called.
    2. You can see one of these in the program I hopefully showed you running in class, which is just below.
  6. Note that this program has many examples of bad form in it.  But it is just a hack to demonstrate some ideas.
    1. You shouldn't be afraid to hack, especially when you are trying to understand something for the first time.
    2. But you should know the difference between hacking and programming.
    3. You should only submit programs for your coursework, not hacks!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

/**
* @author joanna
*
* Illustrates how to catch exceptions, as well as command line I/O.
*
*/
public class BeBadIndex {

public static void main(String[] args) {
ArrayList myStuff = new ArrayList();

myStuff.add(new Integer(5)); // will be the 0th element.
myStuff.add(new Integer(7));
myStuff.add(new Integer(13));
myStuff.add(new Integer(2));


int newIx = -1;
try {
BufferedReader stdin =
new BufferedReader(new InputStreamReader(System.in));
String myNumString;

System.out.print("Welcome to my program. The prompt looks like >." +
"\n >> ");
while ((myNumString=stdin.readLine()) != null) {
try { // this is the bit you saw earlier...
newIx = Integer.decode(myNumString).intValue();
} catch (NumberFormatException nfe) {
System.out.println("er, you were meant to put in integers! Maybe I need more documentation.");
newIx = 0; // give newIx a value that won't crash the program
} catch (Exception ex) {
System.out.println("Wow, I didn't expect a " + ex);
} finally { // this prints out whether there's an error or not!
System.out.println("I have " + newIx + " as my index.");
System.out.flush();
}
try {
System.out.println("The value at " + newIx +
" is " + myStuff.get(newIx));
} catch (IndexOutOfBoundsException iobe) {
System.out.println("We're sorry, " +
"there is no such array element.");
}

System.out.print("\n >> ");
} // while reading
} catch (IOException ioe) {
ioe.printStackTrace();
System.exit(-3);
}
}
}


V. Throwing Throwables

  1. Syntax is pretty obvious (note -- java hashes won't throw an exception for this, that's why we might have to if we don't want null hash keys!):
    if (key == null) {
    throw new NullPointerException("null key in someBadPlaceForNulls");
    } else {
    return myHash.get(key)
    }
  2. Notice you have to create a new instance of the throwable object.
  3. String offers some diagnostics, will print if the object is printed.
  4. Should also declare this in documentation to warn programmers who use your class!  @throws will wind up in the java doc.
    @throws NullPointerException if the key is null
  5. If the exception is checked, then you must declare it in the method header:
    public void saveToFile(String myFileName)
    throws IOException
  6. Sometimes you just rethrow (propagate) an error you've caught:
    1. Satisfies the obligation for checked error.
    2. Allow calling function to handle.
    3. This is done automatically, implicitly with unchecked errors that aren't handled otherwise.
    4. Generally prefer the implicit handling of unchecked errors, makes code easier to read.
  7. Sometimes you may want to catch one error & throw another,
    1. e.g. to translate from a database layer of a program up to the GUI interface.
  8. Can define new exception classes.
    1. Allows for more information / diagnostics /  documentation.
    2. But can be confusing -- proliferation of names.
    3. Be sure to subclass off of something appropriate!

VI. Summary

  1. Program execution can jump around.
  2. In Java (and most modern languages) the way it can jump is severely limited & controlled in order to make code easier to understand.
  3. Java has exceptionally good error handling (that's the generic term, though you usually actually handle what Java calls "exceptions").
  4. The Blue J chapter on this topic is very, very good, you should read it!

page author: Joanna Bryson
13 Feb 2007