Exceptions in JAVA(JAVA的异常)
JAVA异常接触的很久了,却没有针对它记下一些什么
这片文章包括Introduce exceptions 、Demonstrate throwing and catching 、Show how to embed info in an exception 、Look at exceptions and the stack 、Define the throws clause 、Talk about checked vs. unchecked 、Describe finally clauses
希望能给再遇到异常时带来一些便利。
Exceptions in Java
A method throws an exception on an abnormal condition that it can't handle
Throwing an exception is like throwing a beeping, flashing red ball
Somewhere, you hope, this ball will be caught and the problem handled
A structured "go to" from a place where an error occurs to a place that knows how to handle the error
Exception Classes
In Java, exceptions are objects: instances of java.lang.Throwable or one of its subclasses.

Exceptions are thrown for errors that can often be caught and handled
Errors are thrown for more serious problems
Your code should throw exceptions
Choosing an Exception Class
When you need to throw an exception, you can choose an already existing exception or make one of your own

2 class TemperatureException extends Exception {
3 }
1 // In file except/ex1/TooColdException.java
2 class TooColdException extends TemperatureException {
3 }
1 // In file except/ex1/TooHotException.java
2 class TooHotException extends TemperatureException {
3 }
Exception class should indicate the type of problem that caused the exception
Often, exception classes may have no fields or methods
Throwing Exceptions
To throw an exception, you use the throw keyword:
throw new TooColdException();
The JVM or Java APIs can throw exceptions as well
Here's an example of code that explicitly throws temperature exceptions:
1 // In file except/ex1/VirtualPerson.java
2 class VirtualPerson {
3
4 private static final int tooCold = 65;
5 private static final int tooHot = 85;
6
7 public void drinkCoffee(CoffeeCup cup) throws
8 TooColdException, TooHotException {
9
10 int temperature = cup.getTemperature();
11 if (temperature <= tooCold) {
12 throw new TooColdException();
13 }
14 else if (temperature >= tooHot) {
15 throw new TooHotException();
16 }
17 //...
18 }
19 //...
20 }
1 // In file except/ex1/CoffeeCup.java
2 class CoffeeCup {
3 // 75 degrees Celsius: the best temperature
4 // for coffee
5 private int temperature = 75;
6 public void setTemperature(int val) {
7 temperature = val;
8 }
9 public int getTemperature() {
10 return temperature;
11 }
12 //...
13 }
Catching Exceptions
To catch an exception in Java, you write a try block with one or more catch clauses:
1 // In file except/ex1/Example1.java
2 class Example1 {
3 public static void main(String[] args) {
4
5 int temperature = 0;
6 if (args.length > 0) {
7 try {
8 temperature =
9 Integer.parseInt(args[0]);
10 }
11 catch(NumberFormatException e) {
12 System.out.println(
13 "Must enter integer as first argument.");
14 return;
15 }
16 }
17 else {
18 System.out.println(
19 "Must enter temperature as first argument.");
20 return;
21 }
22
23 // Create a new coffee cup and set the
24 // temperature of its coffee.
25 CoffeeCup cup = new CoffeeCup();
26 cup.setTemperature(temperature);
27
28 // Create and serve a virtual customer.
29 VirtualPerson cust = new VirtualPerson();
30 VirtualCafe.serveCustomer(cust, cup);
31 }
32 }
The lower case character e is a reference to the thrown (and caught) NumberFormatException object
Can also have multiple catch clauses:
1 // In file except/ex1/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(VirtualPerson cust,
5 CoffeeCup cup) {
6
7 try {
8 cust.drinkCoffee(cup);
9 System.out.println("Coffee is just right.");
10 }
11 catch (TooColdException e) {
12 System.out.println("Coffee is too cold.");
13 // Deal with an irate customer...
14 }
15 catch (TooHotException e) {
16 System.out.println("Coffee is too hot.");
17 // Deal with an irate customer...
18 }
19 }
20 }
Catch clauses are examined in their order of appearance in the source file
Matching Exceptions
A catch clause for a superclass type will catch a thrown subclass exception.
1 // In file except/ex2/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(
5 VirtualPerson cust, CoffeeCup cup) {
6
7 try {
8 cust.drinkCoffee(cup);
9 System.out.println(
10 "Coffee is just right.");
11 }
12 catch (TemperatureException e) {
13 // This catches TooColdException,
14 // TooHotException, as well as
15 // TemperatureException.
16 System.out.println(
17 "Coffee is too cold or too hot.");
18 // Deal with an irate customer...
19 }
20 }
21 }
Catch clauses for subclass types must precede catch clauses for superclass types. Thus, this won't compile:
1 // In file except/ex3/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(
5 VirtualPerson cust, CoffeeCup cup) {
6
7 try {
8 cust.drinkCoffee(cup);
9 System.out.println(
10 "Coffee is just right.");
11 }
12 catch (TemperatureException e) {
13 // This catches TooColdException,
14 // TooHotException, as well as
15 // TemperatureException.
16 System.out.println(
17 "Coffee is too cold or too hot.");
18 // Deal with an irate customer...
19 }
20 // THIS WON'T COMPILE, BECAUSE THIS
21 // CATCH CLAUSE WILL NEVER BE REACHED.
22 catch (TooColdException e) {
23 System.out.println(
24 "Coffee is too cold.");
25 }
26 }
27 }
This alternate ordering compiles fine:
1 // In file except/ex4/VirtualCafe.java
2 // This class compiles fine.
3 class VirtualCafe {
4
5 public static void serveCustomer(
6 VirtualPerson cust, CoffeeCup cup) {
7
8 try {
9 cust.drinkCoffee(cup);
10 System.out.println(
11 "Coffee is just right.");
12 }
13 catch (TooColdException e) {
14 System.out.println(
15 "Coffee is too cold.");
16 // Deal with an irate customer...
17 }
18 catch (TemperatureException e) {
19 // This catches TooHotException as well
20 // as TemperatureException.
21 System.out.println(
22 "There's temperature trouble in this coffee.");
23 // Deal with an irate customer...
24 }
25 }
26 }
Embedding Information in an Exception
A thrown exception doesn't just transfer control from one part of your program to another (a "structured go-to"), 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:
1 // In file except/ex5/UnusualTasteException.java
2 class UnusualTasteException extends Exception {
3 public UnusualTasteException() {
4 }
5 public UnusualTasteException(String msg) {
6 super(msg);
7 }
8 }
Client programmers could then create an instance in either of two ways: new UnusualTasteException();
// or
new UnusualTasteException("This coffee tastes like tea.");
A catch clause can then query the object for a detail string, like this:
1 // In file except/ex5/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(
5 VirtualPerson cust, CoffeeCup cup) {
6
7 try {
8 cust.drinkCoffee(cup);
9 System.out.println(
10 "Coffee tastes just right.");
11 }
12 catch (UnusualTasteException e) {
13 System.out.println(
14 "Customer is complaining of an unusual taste.");
15 String s = e.getMessage();
16 if (s != null) {
17 System.out.println(s);
18 }
19 // Deal with an unhappy customer...
20 }
21 }
22 }
Embedding More than a String
If you need more than a String, you can add data and access methods to your exception class:
1 // In file except/ex6/TemperatureException.java
2 abstract class TemperatureException
3 extends Exception {
4
5 private int temperature; // in Celsius
6 public TemperatureException(int temperature) {
7 this.temperature = temperature;
8 }
9 public int getTemperature() {
10 return temperature;
11 }
12 }
1 // In file except/ex6/TooColdException.java
2 class TooColdException
3 extends TemperatureException {
4
5 public TooColdException(int temperature) {
6 super(temperature);
7 }
8 }
1 // In file except/ex6/TooHotException.java
2 class TooHotException
3 extends TemperatureException {
4
5 public TooHotException(int temperature) {
6 super(temperature);
7 }
8 }
The temperature field of the exception object must be set when the object is created, as in: 1 // In file except/ex6/VirtualPerson.java
2 class VirtualPerson {
3
4 private static final int tooCold = 65;
5 private static final int tooHot = 85;
6
7 public void drinkCoffee(CoffeeCup cup) throws
8 TooColdException, TooHotException {
9
10 int temperature = cup.getTemperature();
11 if (temperature <= tooCold) {
12 throw new TooColdException(temperature);
13 }
14 else if (temperature >= tooHot) {
15 throw new TooHotException(temperature);
16 }
17 //...
18 }
19 //...
20 }
A catch clause can then easily determine the actual temperature of the coffee and act accordingly, as in:
1 // In file except/ex6/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(
5 VirtualPerson cust, CoffeeCup cup) {
6
7 try {
8 cust.drinkCoffee(cup);
9 System.out.println("Coffee is just right.");
10 }
11 catch (TooColdException e) {
12
13 int temperature = e.getTemperature();
14 System.out.println("Coffee temperature is "
15 + temperature + " degrees Celsius.");
16
17 if (temperature > 55 && temperature <= 65) {
18
19 System.out.println(
20 "Coffee is cooling off.");
21 // Add more hot coffee...
22 }
23 else if (temperature > 0
24 && temperature <= 55) {
25
26 System.out.println("Coffee is too cold.");
27 // Give customer a new cup of coffee with
28 // the proper temperature...
29 }
30 else if (temperature <= 0) {
31
32 System.out.println("Coffee is frozen.");
33 // Deal with an irate customer...
34 }
35 }
36 catch (TooHotException e) {
37
38 int temperature = e.getTemperature();
39 System.out.println("Coffee temperature is "
40 + temperature + " degrees Celsius.");
41 if (temperature >= 85 && temperature < 100) {
42 System.out.println("Coffee is too hot.");
43 // Ask customer to let it cool a
44 // few minutes...
45 }
46 else if (temperature >= 100
47 && temperature < 2000) {
48
49 System.out.println(
50 "Both coffee and customer are steamed.");
51 // Deal with an irate customer...
52 }
53 else if (temperature >= 2000) {
54
55 System.out.println(
56 "The coffee is basically plasma.");
57 // Deal with a very irate customer...
58 }
59 }
60 }
61 }
Exceptions and the Method Invocation Stack
Code inside a try block is "surrounded" by the catch clauses
Can nest try blocks inside try blocks, building up more layers of catch clauses that surround the code
When a method is invoked from within a try block, that try block's catch clauses surround the code in the invoked method too
When an exception is thrown, the surrounding catch clauses are examined in inside-out order
An exception may be thrown far up the method invocation stack before landing in a catch clause that can handle it
A Method Invocation Stack Example

Simple exception classes: // In file TemperatureException.java
1 // In file except/ex7/TemperatureException.java
2 class TemperatureException extends Exception {
3 }
1 // In file except/ex7/TooColdException.java
2 class TooColdException
3 extends TemperatureException {
4 }
1 // In file except/ex7/TooHotException.java
2 class TooHotException
3 extends TemperatureException {
4 }
1 // In file except/ex7/UnusualTasteException.java
2 class UnusualTasteException extends Exception {
3 }
The drinkCoffee() method of VirtualPerson throws exceptions randomly: 1 // In file except/ex7/VirtualPerson.java
2 class VirtualPerson {
3
4 public void drinkCoffee(CoffeeCup cup)
5 throws TooColdException,
6 TemperatureException,
7 UnusualTasteException {
8
9 try {
10 int i = (int) (Math.random() * 4.0);
11 switch (i) {
12 case 0:
13 throw new TooHotException();
14
15 case 1:
16 throw new TooColdException();
17
18 case 2:
19 throw new UnusualTasteException();
20
21 default:
22 throw new TemperatureException();
23 }
24 }
25 catch (TooHotException e) {
26 System.out.println(
27 "This coffee is too hot.");
28 // Customer will wait until it cools
29 // to an acceptable temperature.
30 }
31 }
32 //...
33 }
If i is zero, drinkCoffee() will throw TooHotException
If i is one, drinkCoffee() will throw TooColdException:
1 // In file except/ex7/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(
5 VirtualPerson cust, CoffeeCup cup)
6 throws TemperatureException,
7 UnusualTasteException {
8
9 try {
10 cust.drinkCoffee(cup);
11 }
12 catch (TooColdException e) {
13 System.out.println(
14 "This coffee is too cold.");
15 // Add more hot coffee...
16 }
17 }
18 }
If i is two, drinkCoffee() will throw UnusualTasteException:
1 // In file except/ex7/Example7.java
2 class Example7 {
3 public static void main(String[] args)
4 throws TemperatureException {
5
6 // Create a new coffee cup.
7 CoffeeCup cup = new CoffeeCup();
8
9 // Create and serve a virtual customer.
10 try {
11 VirtualPerson cust = new VirtualPerson();
12 VirtualCafe.serveCustomer(cust, cup);
13 }
14 catch (UnusualTasteException e) {
15 System.out.println(
16 "This coffee has an unusual taste.");
17 }
18 }
19 }
If i is three or four, drinkCoffee() will throw TemperatureException:
TemperatureException
at VirtualPerson.drinkCoffee(VirtualPerson.java:20)
at VirtualCafe.serveCustomer(VirtualCafe.java:9)
at Example7.main(Example7.java:12)
The Throws Clause
Java requires that a method declare in a throws clause the exceptions that it may throw
A method's throws clause indicates to client programmers what exceptions they may have to deal with when they invoke the method
Only exceptions that will cause a method to complete abruptly should appear in its throws clause:
1 // In file except/ex7/VirtualPerson.java
2 class VirtualPerson {
3
4 public void drinkCoffee(CoffeeCup cup)
5 throws TooColdException,
6 TemperatureException,
7 UnusualTasteException {
8
9 try {
10 int i = (int) (Math.random() * 4.0);
11 switch (i) {
12 case 0:
13 throw new TooHotException();
14
15 case 1:
16 throw new TooColdException();
17
18 case 2:
19 throw new UnusualTasteException();
20
21 default:
22 throw new TemperatureException();
23 }
24 }
25 catch (TooHotException e) {
26 System.out.println(
27 "This coffee is too hot.");
28 // Customer will wait until it cools
29 // to an acceptable temperature.
30 }
31 }
32 //...
33 }
The calling method must either catch the exception or declare it in its own throws clause:
1 // In file except/ex7/VirtualCafe.java
2 class VirtualCafe {
3
4 public static void serveCustomer(
5 VirtualPerson cust, CoffeeCup cup)
6 throws TemperatureException,
7 UnusualTasteException {
8
9 try {
10 cust.drinkCoffee(cup);
11 }
12 catch (TooColdException e) {
13 System.out.println(
14 "This coffee is too cold.");
15 // Add more hot coffee...
16 }
17 }
18 }
1 // In file except/ex7/Example7.java
2 class Example7 {
3 public static void main(String[] args)
4 throws TemperatureException {
5
6 // Create a new coffee cup.
7 CoffeeCup cup = new CoffeeCup();
8
9 // Create and serve a virtual customer.
10 try {
11 VirtualPerson cust = new VirtualPerson();
12 VirtualCafe.serveCustomer(cust, cup);
13 }
14 catch (UnusualTasteException e) {
15 System.out.println(
16 "This coffee has an unusual taste.");
17 }
18 }
19 }
Overridden methods can only throw exceptions declared in the throws clause of the superclass's implementation of the method or subclasses of those exceptions
Checked and Unchecked Exceptions
Only checked exceptions need appear in throws clauses
Whether an exception is "checked" or "unchecked" is determined by its position in the hierarchy of throwable classes:

Placing an exception in a throws clause forces client programmers who invoke your method to deal with the exception, either by:
Catching it, or
Declaring it in their own throws clause
Finally Clauses
Many ways to exit a block:
Execute past closing curly brace.
Execute a
break, continue, or return.
Exit because of a thrown exception.
To ensure that something happens (such as closing a file) upon exiting a block, no matter how the block is exited, use a finally clause:
try {
// Block of code with multiple
// exit points
}
finally {
// Block of code that must always
// be executed when the try block
// is exited, no matter how the
// try block is exited
}
Every try must have at least one catch or finally. If both, finally must go last:
1 // In file except/ex8/VirtualPerson.java
2 class VirtualPerson {
3
4 public void drinkCoffee(CoffeeCup cup) {
5
6 try {
7 int i = (int) (Math.random() * 4.0);
8 switch (i) {
9 case 0:
10 throw new TooHotException();
11
12 case 1:
13 throw new TooColdException();
14
15 case 2:
16 throw new UnusualTasteException();
17
18 default:
19 System.out.println("This coffee is great!");
20 }
21 }
22 catch (TooHotException e) {
23 System.out.println("This coffee is too hot.");
24 }
25 catch (TooColdException e) {
26 System.out.println("This coffee is too cold.");
27 }
28 catch (UnusualTasteException e) {
29 System.out.println(
30 "This coffee is too strong.");
31 }
32 finally {
33 System.out.println(
34 "Can I please have another cup?");
35 }
36 }
37 //...
38 }
If a TooColdException exception is thrown:
This coffee is too cold.
Can I please have another cup?
Exiting a finally clause with a
break, continue, return, or thrown exception overrules the reason the try block was exited.