Exceptions
Home - About Us
 

When something goes horribly wrong in your Java application, one way to handle that situation is to "throw an exception". An Exception-based object is created, the object is filled with information about the error that just occurred, and then the Exception object is thrown. Another part of the Java program is setup to received, or catch, the thrown exception. The receiving code takes any required actions in response to the error, then processing continues normally (from the place in the program where the exception was caught).

There are many pre-written Java exception classes. You can use these, or create your own exception classes.

Example

Let's say that we have a JTextField object, and the user is supposed to enter a numeric value in that text field. The intent is to convert the input String to a int. However, if the user accidentilly types in something that can't be converted (such as "Hi there!" instead of something like "37") then the Integer.parseInt conversion method will throw a NumberFormatException exception. Your code should be ready to catch the thrown exception, if necessary.

The following example does not use exception handling. It works fine as long as the input is correct -- it acts unreliably when incorrect text is entered (i.e., it acts unrelably if the text contains characters that cannot be converted into integers). When I was preparing these notes and I ran the following applet, it the applet "froze" my web browser when faulty input was entered. An applet is a Java window that runs inside of a web browser. The init method is roughly equivalent to a constructor for the applet.

// 

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class EventSample1 extends JApplet implements ActionListener
{
   JTextField tfIn;
   JTextField tfTwice;
   
   public void init()
   {
      setLayout(new FlowLayout());
      
      tfIn = new JTextField(20);
      add(tfIn);
      tfIn.addActionListener(this);

      tfTwice = new JTextField(20);
      add(tfTwice);
      tfTwice.setEditable(false);
   }

   public void actionPerformed(ActionEvent e)
   {
      if (e.getSource() == tfIn)
      {
         int i;
         i = Integer.parseInt(tfIn.getText());
         tfTwice.setText("" + (2 * i));
      }
   }
}

A better version of this applet would catch the thrown exception (the exception thrown by parseInt when bad input is processed).

// 

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class EventSample2 extends JApplet implements ActionListener
{
   JTextField tfIn;
   JTextField tfTwice;
   
   public void init()
   {
      setLayout(new FlowLayout());

      tfIn = new JTextField(20);
      add(tfIn);
      tfIn.addActionListener(this);

      tfTwice = new JTextField(20);
      add(tfTwice);
      tfTwice.setEditable(false);
   }

   public void actionPerformed(ActionEvent e)
   {
      if (e.getSource() == tfIn)
      {
         int i;
         try 
         {
            i = Integer.parseInt(tfIn.getText());  // exception thrown here
            tfTwice.setText("" + 2 * i);
         }
         catch(NumberFormatException numExc)
         {
            tfIn.setText("Invalid input - enter digits only");
            tfTwice.setText("");
         }
      }
   }
}

You can also ask the exception object for its string (call the object's toString method, either explicitly or implicitly), which hopefully gives a decent description of the error. In the next example, the exception object's string is put into the input TextField on an error (versus the message "Invalid input - enter digits only", as in the above example).

// 
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class EventSample3 extends JApplet implements ActionListener
{
   JTextField tfIn;
   JTextField tfTwice;
   
   public void init()
   {
      setLayout(new FlowLayout());

      tfIn = new JTextField(60);
      add(tfIn);
      tfIn.addActionListener(this);

      tfTwice = new JTextField(60);
      add(tfTwice);
      tfTwice.setEditable(false);
   }

   public void actionPerformed(ActionEvent e)
   {
      if (e.getSource() == tfIn)
      {
         int i;
         try 
         {
            i = Integer.parseInt(tfIn.getText());
            tfTwice.setText("" + 2 * i);
         }
         catch(NumberFormatException numExc)
         {
            tfIn.setText(numExc.toString());
            tfTwice.setText("");
         }
      }
   }
}

Exercises

  1. If there is a problem in parseInt, does the line "tfTwice.setText("" + 2 * i);" get executed?
  2. If there is NOT a problem in parseInt, does the line "tfTwice.setText("" + 2 * i);" get executed?
  3. If the catch statement was entered as "catch(IllegalArgumentException numExc)", would the exception get caught on bad input?
  4. If the catch statement was entered as "catch(InstantiationException instExc)", would the exception get caught on bad input?
  5. If the catch statement was entered as "catch(ArithmeticException numExc)", would the exception get caught on bad input?
  6. What about "catch(RuntimeException fe)"?
  7. What is the most general exception class that you could put in this catch phrase (to catch bad input)?

You can throw your own exception objects from your code

Let's start with a simple application that is going to try out a new method I wrote called "UpperCaseFirstLetter" (it converts a String's first character to upper case).

// 
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class EventSample4a extends JApplet implements ActionListener
{
   JTextField tfIn;
   JTextField tfOut;
   
   public void init()
   {	
      setLayout(new FlowLayout());
      tfIn = new JTextField(20);
      add(tfIn);
      tfIn.addActionListener(this);

      tfOut = new JTextField(40);
      add(tfOut);
      tfOut.setEditable(false);
   }

   public void actionPerformed(ActionEvent e)
   {
      if (e.getSource() == tfIn)
      {
         String sResult = 
            UpperCaseFirstLetter(tfIn.getText());
         tfOut.setText(sResult);
      }
   }

   public String UpperCaseFirstLetter (String s) 
   {
      if (s == "")
         return "";

      String s1st = s.substring(0,1).toUpperCase();
      String sRest = "";

      if (s.length() > 1)
         sRest = s.substring(1, s.length());

      return s1st + sRest;
   }
}

Unfortunately, this function doesn't take into one of my great hatreds -- long words! I like short, easy words. Big words are bad! So --- I decide that my UpperCaseFirstLetter method will throw an exception any time it encounters unaccepatably long words! I create three exceptions for my cause: MyKindOfBadException, MyReallyBadException, and MyReallyREALLYHorribleException.

class MyKindOfBadException extends Exception
{
	public String toString()
	{
		return "Kind of bad";
	}
}

class MyReallyBadException extends MyKindOfBadException
{
	public String toString()
	{
		return "Really bad";
	}
}

class MyReallyREALLYHorribleException extends MyReallyBadException
{
	public String toString()
	{
		return "Really, oh, REALLY HORRIBLE!";
	}
}

I'll throw these, as needed in my UpperCaseFirstLetter. See the new version of UpperCaseFirstLetter in the applet, below.

// 
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class MyKindOfBadException extends Exception
{
   public String toString()
   {
      return "Kind of bad";
   }
}

class MyReallyBadException extends MyKindOfBadException
{
   public String toString()
   {
      return "Really bad";
   }
}

class MyReallyREALLYHorribleException extends MyReallyBadException
{
   public String toString()
   {
      return "Really, oh, REALLY HORRIBLE!";
   }
}

public class EventSample4 extends JApplet implements ActionListener
{
   JTextField tfIn;
   JTextField tfOut;
   
   public void init()
   {
      setLayout(new FlowLayout());

      tfIn = new JTextField(20);
      add(tfIn);
      tfIn.addActionListener(this);

      tfOut = new JTextField(40);
      add(tfOut);
      tfOut.setEditable(false);
   }

   public void actionPerformed(ActionEvent e)
   {
      if (e.getSource() == tfIn)
      {
         try 
         {
            String sResult = 
              UpperCaseFirstLetter(tfIn.getText());
            tfOut.setText(sResult);
         }
         catch(MyKindOfBadException myExc)
         {
            tfOut.setText("Just caught exc:  " + myExc.toString());
         }
      }
   }

   public String UpperCaseFirstLetter (String s) throws MyKindOfBadException 
   {
      if (s == "")
         return "";

      // I don't like long words!
      if (s.length() > 5)
         throw new MyReallyREALLYHorribleException();
      else if (s.length() > 4)
         throw new MyReallyBadException();
      else if (s.length() > 3)
         throw new MyKindOfBadException();


      String s1st = s.substring(0,1).toUpperCase();
      String sRest = "";

      if (s.length() > 1)
         sRest = s.substring(1, s.length());

      return s1st + sRest;
   }
}

Exercises

  1. Grab the source code from EventSample4, and add several catch blocks. Try the blocks with different levels of My... exceptions. Try the exceptions in different orders. Add an identifier to the start of each block's message so that you can tell which block the message came from, such as:
    			catch(MyKindOfBadException myExc)
    			{
    				tfOut.setText("catch 1 (kind of):  " + myExc.toString());
    			}
    			catch(MyReallyBadException myExc)
    			{
    				tfOut.setText("catch 2 (ReallyBad):  " + myExc.toString());
    			}
    
  2. While still using the version of UpperCaseFirstLetter that throws my exceptions, remove the try and catch blocks from actionPerformed. What happens?
  3. Grab the source code from EventSample4, and change the line
    	public String UpperCaseFirstLetter (String s) throws MyKindOfBadException
    	
    to
    	public String UpperCaseFirstLetter (String s) throws MyReallyREALLYHorribleException 
    	
    What happens when you run the program?
Home - About Us
Copyright © 2006 by Kiowok, Ann Arbor, Michigan, USA