前言
异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器。
异常错误
通常有以下几种错误:
- 用户输入错误
- 设备错误
- 硬件限制
- 代码错误
异常分类
派 生 于 Error 类 或 RuntimeException 类的所有异常称为非受查
( unchecked ) 异常,所有其他的异常称为受查( checked) 异常。
Error 类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误。 应用程序不应该抛出这种类型的对象。RuntimeException由于不可预测的原因所引发的异常的基类
异常对象都是派生于 Throwable 类的一个实例,内置的异常类不能够满足需求,用户可以创建自己的异常类
异常具体情况
派生于 RuntimeException 的异常包含下面几种情况:
- 错误的类型转换
- 数组访问越界 i
- 访问 null 指针
不是派生于 RuntimeException 的异常包括:
- 试图在文件尾部后面读取数据
- 试图打开一个不存在的文件
- 试图根据给定的字符串查找 Class 对象, 而这个字符串表示的类并不存在
具体抛出异常的代码实例
public Fi1elnputStream(String name) throws FileNotFoundException
有多个IOException异常,可连续抛出
public Image loadlmage(String s) throws FileNotFoundException, EOFException
一个方法必须声明所有可能抛出的受查异常, 而非受查异常要么不可控制( Error),要么就应该避免发生( RuntimeException)。如果方法没有声明所有可能发生的受查异常, 编译器就会发出一个错误消息。
与c++比较
1.在 C++ 中, 如果没有给出 throw 说明, 函数可能会抛出任何异常。而在 Java中, 没有 throws 说明符的方法将不能抛出任何受查丼常
2.代码区分比较
catch (Exception e) // ]ava
catch (Exception* e) // C++
是一样的
抛出异常
1.找到一个合适的异常类。
2.创建这个类的一个对象。
3.将对象抛出。
throw new EOFException();
//~~等同于~~
EOFException e = new EOFException();
throw e;
捕获异常
捕获单个异常
需使用try,catch结合使用
try中的代码段抛出一个在 catch 子句中某个异常类,程序将跳过 try段的其余代码,执行 catch 子句中的异常代码
try 中的代码没有拋出任何异常,跳过 catch 子句
import java.io.*;
class Test1{
public static void main(String[] args) {
File file =new File("C:\\Users\\86135\\Desktop\\text4.txt"); //创建File类对象,并不是实际路径,即使路径错了也不会报错,还未与计算机读写关联,此处单纯是产生File对象。
try {
InputStream in = new FileInputStream("C:\\Users\\86135\\Desktop\\text4.txt");//建立连接创建fileInputStream对象,此处必须为实际路径,否则会抛出异常
System.out.println("没有错误");
}
catch (IOException exception) {
System.out.println("有错误");
//exception.printStackTrace();//不仅打印出异常名字还是显示出位置
//exception.getMessage();//打印出具体异常的名字。不显示具体位置,不方便调试程序。
} }
}
或者是
import java.io.*;
class Test1{
public static void main(String[] args) throws Exception{
File file =new File("C:\\Users\\86135\\Desktop\\text4.txt"); //创建File类对象,并不是实际路径,即使路径错了也不会报错,还未与计算机读写关联,此处单纯是产生File对象。
InputStream in = new FileInputStream("C:\\Users\\86135\\Desktop\\text4.txt");//建立连接创建fileInputStream对象,此处必须为实际路径,否则会抛出异常
System.out.println("没有错误");
}
}
这两种异常使用方式功能是一样的
对比:
1.如果方法中的任何代码拋出了一个在 catch 子句中没有声明的异常类型,那么这个方法就会立刻退出,而throws则为编译器处理异常
2.如果想传递一个异常, 就必须在方法的首部添加一个 throws 说明符, 以便告知调用者这个方法可能会抛出异常。将异常直接交给能够胜任的处理器进行处理更好。
3.阅读Java API 文档, 知道各个方法可能会抛出哪种异常,决定使try/catch,还是添加到 throws 列表中。
捕获多个异常
try
{
//代码中可能抛出的异常
}
catch (FileNotFoundException e) {
//关于文件路径的不对的异常处理
}
catch (IOException e) {
//关于输入输出的异常处理问题
}
..........................
如果捕获异常不存在符属关系,可以在同个catch用多个异常
try
{
//代码中可能抛出的异常
}
catch (FileNotFoundException|IOException e ) {
//关于文件路径的不对的异常处理或者关于输入输出的异常处理问题
}
..........................
捕获多个异常不仅会让你的代码看起来更简单, 还会更高效。 生成的字节码只包含一个对应公共 catch 子句的代码块。
finally结构
不管是否有异常被捕获,finally 中的代码都被执行
当发生异常,关闭所有数据库的连接是非常重要的
在需要关闭资源时, 使用 finally 是不错的选择
InputStream in = new FileInputStream(. . .);
try{
//代码中可能抛出的异常
}
catch (IOException e) {
//关于输入输出异常处理的代码块
}
finally
{
in.close();
}
使用这种解耦合的代码快更加合适
内层try确保关闭输入流,外层的 try 确保报告出现的错误
InputStrean in = . . .;
try
{
try{
//代码中可能抛出的异常
}
finally
{
in.close();
}
}
catch (IOException e) {
//关于输入输出异常处理的代码块
}
注意事项
1.有时候try/finally有时候也会遇到错误,再关闭数据流的时候也会抛出异常,而原先在try中遇到的异常则会丢失,也是一个麻烦的问题
2.在使用try/finally时,如果try和finally都有return结构,最终finally的return语句结果会覆盖try的return语句
异常相关信息
1.打印出异常名字还是显示出位置
e.printStackTrace();
2.打印出具体异常的名字。不显示具体位置
e.getMessage();
3.显示异常对象的实际类型
e.getClass().getName();
总结
1.使用throws异常还是用try/catch抛出异常,具体看情况
2.返回-1或者空栈,最好用异常处理机制抛出好一些
3.利用异常的层次结构,抛出具体的子类异常或者自已创建一个异常类
4.不要过分细化异常,将每条语句都分别放在try中,应该直接都放在try中
以上异常