【JAVA核心技术卷一】Exception异常
来源:互联网 发布:spss数据统计分析实例 编辑:程序博客网 时间:2024/06/05 09:22
Exception异常
异常分类:
- Throwable
- Error
- Exception
- OtherException
- Runtime Exception
异常对象都是派生于Throwable
类的一个实例,但在下一层立即分解为两个分支:Error
和Exception
Error
类层次结构描述了Java
运行时系统的内部错误和资源耗尽错误。如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力。
Exception
层次结构又分解为两个分支:一个派生于RuntimeException
;另一个分支包含其他Exception
。两个分支划分的规则是:由程序错误导致的异常属于RuntimeException
;而程序本身没有问题,但由于像I/O这种错误问题导致的属于其他的异常。
派生于RuntimeException
的异常包含以下几种情况:
- 错误的类型转换
- 数组访问越界
- 访问空指针
不是派生于RuntimeException
的异常包括:
- 试图在文件尾部后面读取数据
- 试图打开一个不存在的文件
- 试图根据给定的字符串查找
Class
对象,而这个字符串表示的类不存在 - ……
“如果出现RuntimeException异常,那么就一定是你的问题”
Java语言规范将派生于Error
类或RuntimeException
类的所有异常称为未检查(unchecked
)异常,所有其他的异常称为已检查(checked
)异常。编译器将核查是否为所有已检查的异常提供了异常处理器。
声明已检查异常
如果遇到了无法处理的情况,可以抛出一个异常。这个道理很简单:一个方法不仅需要告诉编译器将要返回什么值,还要告诉编辑器可能会发生什么错误。
例如:
public FileInputStream(String name) throws FileNotFoundException
这个声明表示这个构造器将根据给定的String
参数产生一个FileInputStream
对象,但也有可能抛出一个FileNotFoundException
异常。如果发生了这种情况,构造器将不会初始化一个新的FileInputStream
对象,而是抛出一个FileNotFoundException
类对象。如果这个方法真的抛出了一个异常对象,运行时系统就会开始搜索异常处理器,一边知道如何处理FileNotFoundException
对象。
在自己编写方法时,不必将所有可能抛出的异常都声明。需要记住在遇到下面4中情况时应该抛出异常:
- 调用一个排除已检查异常的方法,例如
FileInputStream
构造器 - 程序运行过程中发现错误,并利用
throw
语句抛出一个已检查异常 - 程序出现错误。例如
ArrayIndexOutOfBoundsException
这样的未检查异常 - Java虚拟机和运行时库出现的内部错误
如果出现前两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。
对于那些可能被他人使用的Java方法,应该在方法的首部声明这个方法可能抛出的异常
public Image loadImage(String s) throws IOException{}
如果一个方法可能抛出多个已检查异常,那么久必须在方法的首部列出所有的异常类,每个异常类用逗号隔开
public Image loadImage(String s) throws FileNotFoundException , EOFException{}
但是,不需要声明Java的内部错误,即从Error继承的错误。同样,也不应该声明从RuntimeException
继承的那些未检查异常
void drawImage(int i) throws ArrayIndexOutOfBoundsException // bad style :(
总之,一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。如果方法没有声明或捕获所有可能发生的已检查异常,编译器就会给出一个错误信息。
如果在子类中覆盖了超类的一个方法,子类方法中声明的已检查异常不能比超类中更通用。如果超类方法中没有抛出任何已检查异常,子类也不能抛出任何已检查异常
如果类中的一个方法声明将会抛出一个异常,而这个异常是某特定类的实例时,则这个方法就由可能抛出一个这个类的异常,或者给这个类的任意一个子类的异常。
如何抛出异常
- 找到一个合适的异常类
- 创建这个类的一个对象
- 将对象抛出
String readData(Scanner in) throws EOFException{ ... if(!in.hasNext()){ //遇到了End of File if(n<len) throw new EOFException(); //注意这里是throw没有s } ...}
一旦方法抛出了异常,这个方法就不可能返回到调用者
也可以自己创建一个异常类
class FileFormatException extends IOException{ ...}
注意!如果调用了一个抛出已检查异常的方法,就必须对它进行处理,或者将它继续传递!
捕获异常
想捕获一个异常,必须设置try/catch
语句
try{ ...}catch(ExceptionType e){ handler}
如果在try
语句块中的任何代码抛出了一个在catch
子句中说明的异常类,那么程序将跳过try
语句块的其余代码,并将执行catch
子句中的处理器代码。
如果在try
语句没有抛出任何异常,那么程序将跳过catch子句
。
如果方法中的任何代码抛出了一个在catch
中没有声明的异常类型,那么这个方法会立刻退出
也可以捕获多个异常:
try{ ...}catch(ExceptionA a){ ...}catch(ExceptionB b){ ...}catch(ExceptionC c){ ...}
捕获多个异常时,异常变量隐含为
final
变量,因此,不能在子句体中为e赋不同 值
catch(ExceptionA|ExceptionB e){...} //error
再次抛出异常与异常链
在catch
子句中可以抛出一个异常,这样做的目的是改变异常的类型。
try{}catch(SQLException e){ throw new ServletException("database error:"+e.getMessage());}
这里,ServleException
用带有异常信息文本的构造器来构造。不过,可以有一种更好的处理方法,并且将原是一场设置为新异常的“原因”:
try{}catch(SQLException){ Throwable se = new ServletException("database error"); se.initCause(e); throw se;}
当捕获到异常时,就可以使用下面这条语句重写得到原始异常
Throwable e = se.getCause();
强烈建议使用这种包装技术,这样可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节。
如果在一个方法中发生了一个已检查异常,而不允许抛出它,那么包装技术就十分有用。我们可以捕获这个已检查异常,并将它包装成一个运行时异常
finally子句
当代码抛出一个异常时,就会终止方法中剩余代码的处理,并推出这个方法的执行。如果想继续执行程序,例如回收获得的本地资源,就要使用finally
子句。
在try
语句中可以只有finally
子句而没有catch
子句
建议独立使用
try/catch
和try/finally
语句块,这样可以提高代码的清晰度
InputStream in = ...;try{ try{ ... }finally{ in.close() }}catch(Exception e){ ...}
内层的
try
语句块只有一个职责,就是确保关闭输入流。外层的try
语句块也只有一个职责,就是确保报告出现的错误。这种设计方式不仅清楚,而且还具有一个功能,就是将会报告finally
子句中出现的错误
当finally
子句中包含return
语句时,将会先执行finally
中的return
语句。
当然,finally
子句也会带来麻烦。例如IO处理时
InputStream in = ...;try{ //code might throw exceptions}finally{ in.close();}
当try
语句块中的代码抛出了一些非IOException
的异常,这些异常只有这个方法的调用者才能够给予处理。执行finally
语句块并调用close
方法。而close
方法本身也有可能抛出IOException
异常。当出现这种情况时,原始的异常将会丢失,转而抛出close
方法的异常。如果你想做适当的处理,重新抛出原来的异常,代码会变得极其繁琐。
InputStream in = ...;Exception ex = null;try{ try{ //code might throw exceptions }catch(Exception e){ ex = e; throw e; }}finally{ try{ in.close(); }catch(Exception e ){ in(ex ==null) throw e; }}
带资源的try
语句
不过在JAVA SE 7中,假设资源属于一个实现了AutoCloseable
接口的类,这个接口有一个方法
void close() throws Exception
另外还有一个
Closeable
接口。这是Autoacloseable
的子接口,也包含一个close
方法,不过这个方法声明为抛出一个IOExcepiton
带资源的try
语句的最简形式为
try(Resource res = ){ //work with res}
try
语句正常退出时,或者存在一个异常时,都会自动调用res.close()
,就好像使用了finally
块一样。
只要需要关闭资源,就要尽可能使用带资源的try
语句
但是,使用异常的基本规则是:只在异常情况下使用异常机制
例如我们检测退栈操作前,要判断栈是否为空
if(!s.empty()){ s.pop();}
如果强行进行退栈操作并捕获异常
try{ s.pop()}catch(EmptyStackException){}
在测试中,调用isEmpty
的运行时间为646毫秒,而捕获EmptyStackException
的运行时间则为21739毫秒
2.不要过分地细化异常
3.利用异常层次结构
4.不要压制异常,即使这个方法有可能100年才抛出一个异常
5.在检查错误时,“苛刻”要比放任更好
6.不要羞耻于传递异常
- 【JAVA核心技术卷一】Exception异常
- Java异常(Java核心技术卷一读书笔记)
- 《Java 核心技术卷一》读书笔记
- java核心技术卷一 读书笔记
- java核心技术卷 之异常分类
- java核心技术卷 之捕获异常
- 2015 7 6 Java核心技术卷一 第11章 异常 断言 日志和调试
- Java核心技术卷一 第11章 异常、断言和日志
- 《Java核心技术(卷一)》读书笔记——第十一章:异常处理
- #Java 核心技术卷一阅读笔记# 第七章 异常、断言和日志
- [学习笔记] Java核心技术 卷一:基础知识 异常、断言和曰志(四)
- Java核心技术 卷I 手记(一)
- java核心技术卷一第八章手敲
- 《java核心技术--卷一》equals方法
- JAVA核心技术卷一,泛型例子
- Java核心技术卷一学习笔记1
- 【JAVA核心技术卷一】Inheritance 继承
- 【JAVA核心技术卷一】Interface 接口
- 友元函数和友元类
- java 水仙花数 提升档次解法
- cf #334 D. Moodular Arithmetic (组合计数)
- onWindowFocusChanged重要作用 及Activity生命周期的详解(对解决某些窗体溢出问题很有帮助)
- 下拉选项样式整理
- 【JAVA核心技术卷一】Exception异常
- github的傻瓜式教学,教你如何上传代码到github
- Tortoise SVN使用方法,简易图解
- maven mirror
- 用tomcat发布javaweb项目
- 菜单栏[MenuStrip]
- 【AndroidStudio】关于SVN的相关配置简介
- XML DOM nextSibling 属性
- percona tpcc的安装和使用