异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器。
如果某个方法不能够采用正常的途径完成它的任务,就可以通过另外一个路径退出方法。这时,方法不会继续执行,也不返回任何值,而是抛出一个封装了错误信息的对象,异常处理机制开始搜索能偶处理这种异常的异常处理器。
异常对象全部派生自Thorwable类。
下面的图表是OCJP的考试要求的几个异常,其实异常比这个要多得多,这只是一个简化的图,表明了各个异常之间的层次关系。
IOException:只有checked异常才有必要throws,即只有IOException异常才有必要thorws。
Error:任何程序代码都有抛出从Error继承的异常的能力,而我们对其没有任何控制能力。
RuntimeException:我们应该避免从RuntimeException继承的异常的发生。
总之,一个方法必须声明所有可能抛出的checked异常,而unchecked异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。
声明已检查(checked,也就是IOException类及其子类)异常
public FileInputStream(String name) throws FileNotFoundException{ }
而已检查异常又分为两种,存在,或者不存在。
对于一个已经存在的异常,
String readData(Scanner in) throws EOFException{ ... while(...){ if(!in.hasNext()){ if(n < len) thorw new EOFException(); } } return s; }
class FileFormatException extends IOException{ public FileFormatException(){} public FileFormatException(String gripe){ super(gripe); }
String readData(BufferedReader in) throws FileFormatException{ ... while(...){ if(ch == -1){ if(n < len) thorw new FileFormatException(); } } return s; }
捕获异常的一般格式
try{ //code } catch(ExceptionType e){ //handler for this type }
java.lang.throwable里面有一个getMessage方法,用来获得Throwable对象的详细信息。
由于FileNotFoundException继承自IOException,所以必须把IOException放到后面,否则编译器会报错(Unreachable catch block for FileNotFoundException. It is already handled by the catch block for IOException)。
package com.xujin; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class Test { public static void main(String [] args){ Test test = new Test(); test.read("fo.in"); } public void read(String fileName){ try{ InputStream in = new FileInputStream(fileName); int b; while((b = in.read()) != -1){ System.out.print(b); } } catch(FileNotFoundException e){ e.printStackTrace(); System.out.println(e.getMessage()); System.out.println(e.getClass().getName()); } catch(IOException e){ e.printStackTrace(); System.out.println(e.getMessage()); System.out.println(e.getClass().getName()); } } }
package com.xujin; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class Test { public static void main(String [] args) throws IOException{ Test test = new Test(); test.read("fo.in"); } public void read(String fileName) throws IOException{ try{ InputStream in = new FileInputStream(fileName); int b; while((b = in.read()) != -1){ System.out.print(b); } } catch(IOException e){ throw new IOException("ERROR, IOException, " + e.getMessage()); } } }
当程序获得了一些本地资源,如果还没有来得及释放就产生异常了,那么就产生了资源回收的问题。
最笨的解决办法是在处理异常的代码catch中回收资源,但这样比较乏味。
这就要使用Finally字句,不管是否有异常被捕获,finally子句都要执行。
如下例子:
不管是否有异常,in.close()都要执行。
public void read(String fileName) throws IOException{ InputStream in = new FileInputStream(fileName); try{ int b; while((b = in.read()) != -1){ System.out.print(b); } } catch(IOException e){ throw new IOException("ERROR, IOException, " + e.getMessage()); } finally{ in.close(); } }
为了提高代码的清晰度,我们可以这样做:
内层try/catch语句的作用是确保关闭输入流,外层try/catch语句的作用是确保报告出现的错误。
public void read(String fileName) throws IOException{ InputStream in = new FileInputStream(fileName); try{ try{ int b; while((b = in.read()) != -1){ System.out.print(b); } } finally{ in.close(); } } catch(IOException e){ throw new IOException("ERROR, IOException, " + e.getMessage()); } }
注意:
public StackTraceElement[] getStackTrace()
printStackTrace()
. Returns an array of stack trace elements, each representing one stack frame. The zeroth element of the array (assuming the array's length is non-zero) represents the top of the stack, which is the last method invocation in the sequence. Typically, this is the point at which this throwable was created and thrown. The last element of the array (assuming the array's length is non-zero) represents the bottom of the stack, which is the first method invocation in the sequence.
Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method. Generally speaking, the array returned by this method will contain one element for every frame that would be printed by printStackTrace
. Writes to the returned array do not affect future calls to this method.
public static Map<Thread,StackTraceElement[]> getAllStackTraces()
getStackTrace
method.
The threads may be executing while this method is called. The stack trace of each thread only represents a snapshot and each stack trace may be obtained at different time. A zero-length array will be returned in the map value if the virtual machine has no stack trace information about a thread.
If there is a security manager, then the security manager's checkPermission method is called with a RuntimePermission("getStackTrace") permission as well as RuntimePermission("modifyThreadGroup") permission to see if it is ok to get the stack trace of all threads.
SecurityException
- if a security manager exists and its checkPermission method doesn't allow getting the stack trace of thread.
getStackTrace()
,
SecurityManager.checkPermission(java.security.Permission)
,
RuntimePermission
,
Throwable.getStackTrace()
public class StackTraceTest { /** Computes the factorial of a number @param n a nonnegative integer @return n! = 1 * 2 * . . . * n */ public static int factorial(int n) { System.out.println("factorial(" + n + "):"); Throwable t = new Throwable(); StackTraceElement[] frames = t.getStackTrace(); for (StackTraceElement f : frames) System.out.println(f); int r; if (n <= 1) r = 1; else r = n * factorial(n - 1); System.out.println("return " + r); return r; } public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.print("Enter n: "); int n = in.nextInt(); factorial(n); } }
ArrayIndexOutOfBoundsException
java.lang.ArrayIndexOutOfBoundsException
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
int[] i = new int[10]; System.out.print(i[12]);//java.lang.ArrayIndexOutOfBoundsException: 12
ClassCastException
java.lang.ClassCastException
类造型异常。假设有类A和B(A是B的父类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。
Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance.
例如:
Object x = new Integer(0); System.out.println((String)x);//Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
IllegalArgumentException
java.lang.IllegalArgumentException
违法的参数异常。一个方法被传递了非法的或者不合适的参数,而调用了该方法时,抛出该异常。
Thrown to indicate that a method has been passed an illegal or inappropriate argument.
IllegalStateException
java.lang.IllegalStateException
违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常。
NullPointerException
java.lang.NullPointerException
空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
String b = null; System.out.print(b.hashCode());//Exception in thread "main" java.lang.NullPointerException
NumberFormatException
java.lang.NumberFormatException
数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。
System.out.println(Integer.parseInt("!123"));//Exception in thread "main" java.lang.NumberFormatException: For input string: "!123"
AssertionError
java.lang.AssertionError
断言错。用来指示一个断言失败的情况。
ExceptionInInitializerError
java.lang.ExceptionInInitializerError
初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段
StackOverflowError
java.lang.StackOverflowError
堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。
NoClassDefFoundError
java.lang.NoClassDefFoundError
未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。