When you throw an exception, you are performing a kind of structured go-to from the place in your program where an abnormal condition was detected to a place where it can be handled. The Java virtual machine uses the class of the exception object you throw to decide which catch clause, if any, should be allowed to handle the exception. But an exception doesn't just transfer control from one part of your program to another, it also transmits information. Because the exception is a full-fledged object that you can define yourself, you can embed information about the abnormal condition in the object before you throw it. The catch clause can then get the information by querying the exception object directly.
The Exception class allows you to specify a String detail message that can be retrieved by invoking getMessage() on the exception object. When you define an exception class of your own, you can give client programmers the option of specifying a detail message like this:
// In Source Packet in file except/ex5/UnusualTasteException.java
class UnusualTasteException extends Exception { UnusualTasteException() { }
UnusualTasteException(String msg) { super(msg);
}
}
Given the above declaration of UnusualTasteException, client programmers could create an instance in one of two ways:
- new UnusualTasteException()
- new UnusualTasteException("This coffee tastes like tea.")
A catch clause can then query the object for a detail string, like this:
// In Source Packet in file except/ex5/VirtualCafe.java
class VirtualCafe { public static void serveCustomer(VirtualPerson cust,
CoffeeCup cup) { try { cust.drinkCoffee(cup);
System.out.println("Coffee tastes just right."); }
catch (UnusualTasteException e) { System.out.println(
"Customer is complaining of an unusual taste.");
String s = e.getMessage();
if (s != null) { System.out.println(s);
}
// Deal with an unhappy customer...
}
}
}
When you need to embed more information into an exception object than you can represent with a String, you can add data and access methods to your exception class. For example, you could define the temperature exception classes like this:
// In Source Packet in file except/ex6/TemperatureException.java
abstract class TemperatureException extends Exception { private int temperature; // in Celsius
public TemperatureException(int temperature) { this.temperature = temperature;
}
public int getTemperature() { return temperature;
}
}
// In Source Packet in file except/ex6/TooColdException.java
class TooColdException extends TemperatureException { public TooColdException(int temperature) { super(temperature);
}
}
// In Source Packet in file except/ex6/TooHotException.java
class TooHotException extends TemperatureException { public TooHotException(int temperature) { super(temperature);
}
}
Given a TemperatureException family as defined above, catch clauses can query the exception object to find out the precise temperature that caused the problem. The temperature field of the exception object must be set when the object is created, as in:
// In Source Packet in file except/ex6/VirtualPerson.java
class VirtualPerson { private static final int tooCold = 65;
private static final int tooHot = 85;
public void drinkCoffee(CoffeeCup cup) throws
TooColdException, TooHotException {
int temperature = cup.getTemperature();
if (temperature <= tooCold) { throw new TooColdException(temperature);
}
else if (temperature >= tooHot) { throw new TooHotException(temperature);
}
//...
}
//...
}
Wherever the exception is caught, the catch clause can easily determine the actual temperature of the coffee and act accordingly, as in:
// In Source Packet in file except/ex6/VirtualCafe.java
class VirtualCafe { public static void serveCustomer(VirtualPerson cust,
CoffeeCup cup) { try { cust.drinkCoffee(cup);
System.out.println("Coffee is just right."); }
catch (TooColdException e) { int temperature = e.getTemperature();