|
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
- If there is a problem in parseInt, does the line "tfTwice.setText("" + 2 * i);" get
executed?
- If there is NOT a problem in parseInt, does the line "tfTwice.setText("" + 2 * i);" get
executed?
- If the catch statement was entered as "catch(IllegalArgumentException numExc)", would the
exception get caught on bad input?
- If the catch statement was entered as "catch(InstantiationException instExc)", would the
exception get caught on bad input?
- If the catch statement was entered as "catch(ArithmeticException numExc)", would the
exception get caught on bad input?
- What about "catch(RuntimeException fe)"?
- 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
- 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());
}
- While still using the version of UpperCaseFirstLetter that throws my exceptions,
remove the try and catch blocks from actionPerformed. What happens?
- 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?
|