一、异常分类
在Java程序设计语言中,异常对象都是派生于Throwable类的一个实例。但在下一层立即分解为两个分
支:Error 和 Exception。
Error 类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误。 应用程序不应该抛出这种类型的对象。 如果出现了这样的内部错误, 除了通告给用户,并尽力使程序安全地终止之外, 再也无能为力了。这种情况很少出现。
在设计 Java 程序时, 需要关注 Exception 层次结构。 这个层次结构又分解为两个分支:一个分支派生于 RuntimeException ; 另一个分支包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于 RuntimeException ; 而程序本身没有问题, 但由于像 I/O 错误这类问题导致的异常属于其他异常。
派生于 RuntimeException 的异常包含下面几种情况:
- 错误的类型转换。
- 数组访问越界。
- 访问 null 指针。
不是派生于 RuntimeException 的异常包括:
- 试图在文件尾部后面读取数据。
- 试图打开一个不存在的文件。
- 试图根据给定的字符串查找 Class 对象, 而这个字符串表示的类并不存在。
“ 如果出现 RuntimeException 异常, 那么就一定是你的问题” 是一条相当有道理的规则。
Java 语 言 规 范 将 派 生 于 Error 类 或 RuntimeException 类的所有异常称为非受查( unchecked ) 异常,所有其他的异常称为受查( checked) 异常。
二、异常的使用
public void exception() throws Exception {
throw new Exception();
}
public void run() {
throw new RuntimeException();
}
三、创建异常类
public class FileFormatException extends IOException{
public FileFormatExceptionO {}
public FileFormatException(String gripe){
super(gripe);
}
}
四、捕获异常
如果某个异常发生的时候没有在任何地方进行捕获,那程序就会终止执行,并在控制台
上打印出异常信息, 其中包括异常的类型和堆栈的内容。
4.1 捕获异常
/** 捕获异常的语法 */
try{
more code
}catch (ExceptionType e){
handlerfor this type
}
4.2 捕获多个异常
try{
code that might throwexceptions
}
catch (FileNotFoundException e){
emergencyactionfor missingfiles
}
catch (UnknownHostException e){
emergency actionfor unknown hosts
}
catch (IOException e){
emergencyactionfor all other I/O problems
}
在 Java SE 7中,
同一个 catch 子句中可以捕获多个异常类型
。例如,假设对应缺少文件
和未知主机异常的动作是一样的,就可以合并 catch 子句:
try{
code that might throw exceptions
}catch (FileNotFoundException | UnknownHostException e){
//捕获多个异常时,异常变量隐含为final变量。例如,不能在以上子句体中为e赋不同的值
emergency action for missing files and unknown hosts
}catch (IOException e){
emergency action for all other I/O problems
}
4.3 再次抛出异常与异常链
在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型。也可能是需要做一些处理之后再次抛出异常。
try{
access the database
}catch (SQLException e){
throw new ServletException("database error: " + e.getMessageO);
}
/* 或使用包装技术 */
try{
access the database
}catch (SQLException e){
Throwable se = new ServletException ("database error");
se.initCause(e)
}
如果在一个方法中发生了一个受查异常, 而不允许抛出它, 那么包装技术就十分
有用。我们可以捕获这个受查异常,并将它包装成一个运行时异常。
4.4 finally子句
不管是否有异常被捕获,finally 子句中的代码都被执行。
try{
more code
}catch (ExceptionType e){
handlerfor this type
}finally{
}
4.5 带资源的try语句
try (Resource res = . . .){
work with res
}
假设资源属于一个实现了 AutoCloseable 接口的类,AutoCloseable 接口有一个方法:
void close() throws Exception
Java SE 7 为这种代码模式提供了一个很有用的快捷方式(带资源的try语句)。try块退出时,会自动调用res.close()。
另外,还有一个 Closeable 接口。这是 AutoCloseable 的子接口, 也包含一个 close方法。不过, 这个方法声明为抛出一个 IOException。
4.6 分析堆栈轨迹元素
堆栈轨迹( stack trace ) 是一个方法调用过程的列表, 它包含了程序执行过程中方法调用的特定位置。当Java 程序正常终止, 而没有捕获异常时, 这个列表就会显示出来。
可以调用 Throwable 类的 printStackTrace 方法访问堆栈轨迹的文本描述信息。
Throwable t = new Throwable();
StringWriter out = new StringWri ter() ;
t.printStackTrace(new PrintWriter(out));
String description = out.toString();
一种更灵活的方法是使用 getStackTrace 方法, 它会得到 StackTraceElement 对象的一个数组, 可以在你的程序中分析这个对象数组。例如:
Throwable t = new ThrowableO ;
StackTraceElement[] frames = t.getStackTrace();
for (StackTraceElement frame : frames)
analyze frame
StackTraceElement 类含有能够获得文件名和当前执行的代码行号的方法, 同时, 还含有能够获得类名和方法名的方法。toString 方法将产生一个格式化的字符串, 其中包含所获得的信息。
静态的 Thread.getAllStackTrace 方法, 它可以产生所有线程的堆栈轨迹 . 下面给出使用这个方法的具体方式:
Map<Thread, StackTraceElement[]> map = Thread.getAl1StackTraces();
for (Thread t : map. keySet ()){
StackTraceElement[] frames = map.get(t);
analyze frames
}
五、总结
5.1 throw 和 throws 的区别
- throw:是真实抛出一个异常。
- throws:是声明可能会抛出一个异常。
5.2 final、finally、finalize 有什么区别?
- final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,则表示此方法和此变量不能在被改变,只能使用。
- finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。
- finalize: 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。
5.3 try-catch-finally 中哪个部分可以省略?
try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。
5.4 try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗
finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。
5.5 常见的异常类有哪些
- NullPointerException 空指针异常
- ClassNotFoundException 指定类不存在
- NumberFormatException 字符串转换为数字异常
- IndexOutOfBoundsException 数组下标越界异常
- ClassCastException 数据类型转换异常
- FileNotFoundException 文件未找到异常
- NoSuchMethodException 方法不存在异常
- IOException IO 异常
- SocketException Socket 异常