如果一个方法有可能抛出多个已检查异常,就必须在方法的首部列出所有的异常类。每个异常类之间用逗号(,)隔开。不需要声明java的内部错误,就是从Error继承的那些异常。任何程序代码都具有抛出这类异常的潜能,而我们对他们没有控制能力。也不应该从声明从RuntimeException继承的那些未检查的异常。
一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(error),要么应该避免它们的发生。如果在子类中覆盖了超过类的方法,那么子类方法中声明的异常不能超过超类方法中声明的异常范围(PS:其实昨天关于这一点疑问,今天前同事,和我说了知道,这里的异常范围的意思一般情况下有两个意思,一是异常其实是也是类,就是子类继承类的范围不能大于父类的继承。二,异常的数量,子类里面的数量,不能比父类里的数量要多。指的是这样两个的情况)
搏获异常:只要将它抛出不需要理睬它了,有些代码必须捕获异常,搏获异常需要周密的计划。要想搏获异常,必须设置try/catch语句块。try语句块的最简单的形式如:
try{
code
more code
more code
}
catch (ExceptionType e){
handler for this type
}
如果try语句中的任何代码抛出了一个在catch子句中指定的异常类,那么程序将跳过try语句块中的其余代码。
如果try语句听任何代码抛出了一个在catch子句中指定的异常类,程序将执行catch子句中的处理器代码。
(两个是同时满足的情况e,就是只要catch抛出异常就又跳过try,又执行catch)。
搏获异常有两种方式:一种是上面的try的简单形式,二是在一个try语句块中搏获多个异常类型。
try {
code that might throw exceptons
}
catch (MalformedURLExcepton e1){
emergency action for malformed URLs
}
catch (UnknownHostException e2{
emergency action for unknown hosts
}
catch (IOException e3){
emergency action for all other I/O problems
}
再次抛出异常与链异常:在一个catch子句中,也可以抛出一个异常,这样做的目的是希望改变异常的类型。用于表示子系统故障的异常类型可能会产生多种解释。ServletException就是这样一个异常类型。捕获异常并再次抛出的基本方法:
try {
access the data base
}
catch (SQLException e){
throw new ServetException("database error:"+e.getMessage());
}
还有一种方法是可以将原始异常设置为新异常的“诱饵”:
try{
access the databse
}
catch (SQLException e){
Throwable se=new ServletException("database error");
se.setCause(e);
throw se;
}
当捕获到异常时,就可以使用下面的这条语句得到原始异常:Throwable e=se.getCause();
finaly子句:当代码抛出一个异常时,就会终止对方法中剩余代码的处理,并退出这个方法。如果方法获得了一些本地资源,并且只有这个方法知道,又如果这些资源在退出方法之前必须被回收,那么就会发生资源回收的问题。java有两种解决方案:一是捕获并重新抛出所有异常。(这种解决方案比较乏味,因为需要在两个地方清除所分配的资源,一个是在正常代码中,一个是在异常代码中)二是用finally子句。不管是否有异常捕获,finally子句中的代码都会被执行。
强烈建议使用try/catch和try/finally语句块,InputSream in=...;
try{
try{
code that might throw exceptions
}
finally {
in.close();
}
}
catch (IOException e){
show error dialog
}
内层的try语句块只有一个职责,就是确保关闭输入流,在外层的try语句块也只有一个职责。就是保证报告出现的错误。这种解决不仅清楚,而且还具有有一个功能,就是报告finally子句中出现的错误。当finally子句包含return语句时,在方法返回之前,finally语句块的内容将会被执行,如果finally语句块中也包含一个return语句,那么这个返回值将会掩盖原来的返回值。
在异常处理方面,java没有析构器(PS:可以说根本就没有析构器这个概念的
),,因而也没有C++的自动回收功能。这就意味着java程序员必须手工地将回收资源的代码放入finally语句中,由于java内置垃圾回收机制,只有极少数资源需要人工进行回收。堆栈跟踪元素分析:堆栈跟踪元素分析是一个方法调用过程的列表,它包含了程序执行中方法调用的特定性置。当程序正常终止,而没有捕获异常时,就会显示这个列表。堆栈跟踪只追踪抛出异常的语句,而不必跟踪错误的根源。
package com.atguigu.app;
import java.util.*;
public class StackTraceTest {
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.println("Enter n:");
int n=in.nextInt();
factorial(n);
}
}
这个程序的实现过程中发生了这样一个错误,在这个部分
java.lang.Throwable中:throwable(Throwable cause)
throwable(String message,Throwable cause)用给定的诱饵”,构造一个throwable对象。
throwable initCause(Throwable cause):将这个对象设置为“诱铒”,如果这个对象已经被设置为“诱铒“,就抛出一个异常。返回this引用 。
throwable getCause():获取这个对象的“诱饵”的异常对象,如果没有设置“诱饵,则返回null”
StackTraceElement[] getStackTrace():获取构造这个对象进调用堆栈的跟踪。
java.lang.exception中:exception(Throwable cause)
Exception(String message.Throwable cause)用给定的诱饵,构造一个Exception
java.lang.runtimeException:runtimeException(Throwable cause)
RuntimeException(String message,Throwable cause)用给定的诱饵构造一个runtimeException对象。
java.lang.StackTraceElement中:String getFileName():返回这个元素运行时对应的源文件名。如果这个信息不存在,则返回null
int getLIneNumber() 返回这个元素运行时对应的源文件名行数。如果这个信息不存在,则返回-1
String getClassName():返回这个元素远行时对应的类的全名
String getMethodName():返回这个元素运行时对应的方法名。构造器史是<int>,表态初始化器名是<clinit>, 这里无法区分同名的重载方法。
boolena isNative Method():如果这个元素运行时在一个本地方法中,刚返回true
String toString():如果存在的话,返回一个包含类名,方法名,文件名和行号的格式化字符串。