简介:
java中的异常处理的目的在于通过使用少量的代码,使得程序有着强大的鲁棒性。可以使程序中的异常处理代码和正常业务代码分离。
java的异常机制主要依赖于五个关键字:try、catch、 finally、 throw、 throws、
try:后紧跟一个花括号扩起来的代码块,,放置可能引发异常的代码
catch:用于处理这种类型的代码,
finally:回收try中打开的物理资源,一定会执行
throws:在方法签名中使用,声明该方法可能抛出的异常
throw:抛出一个实际的异常
1、异常处理机制
1.1、使用try...catch捕获异常
try {
//业务实现代码
}
catch (Exception e){
//异常处理代码
}
如果在执行try块里的业务逻辑代码时出现了异常,系统会自动生成一个异常对象,该异常对象被提交给java运行时环境,此过程被称为抛出异常
异常对象交给catch块处理,这个过程称为:捕获异常
注意:如果出现异常的代码块没有被try...catch包含,则也会生成一个异常对象,但是无法找到处理该异常的catch块,程序就会异常退出
1.2、异常类的继承体系
try块后可以跟多个catch块。
运行代码过程中,发生不同的意外,抛出的异常对象不同。java收到异常对象后,会依次判断该异常对象是否是catch块后异常类或者其子类的事例,找到合适的catch执行
执行过程如下图所示:
代码事例如下:
try{ int a=Integer.parseInt(args[0]); int b=Integer.parseInt(args[1]); int c=a/b; System.out.println("c的结果为:"+c); } catch (IndexOutOfBoundsException ie){ System.out.println("数组出界"); } catch(NumberFormatException ne){ System.out.println("数字格式不正确"); } catch(ArithmeticException ae){ System.out.println("算数异常,分母为0"); } catch (Exception e){ System.out.println("其他错误"); }
java提供多个异常类,之间都有继承关系,如下图所示:
1.3、多捕获异常:使用一个catch块捕获多个异常,多种类型异常之间用“|”隔开,且异常变量默认为final类型,不能被改变。例如:
try{
int a=Integer.parseInt(args[0]);
int b=Integer.parseInt(args[1]);
int c=a/b;
System.out.println("c的结果为:"+c);
}
catch(IndexOutOfBoundsException|NumberFormatException|ArithmeticException ie){
System.out.println("异常");
//ie=new ArithmeticException("test"); 此行会不通过编译,因为ie对象为final类型,不能被修改
}
1.4、访问异常信息
getMessage();返回该异常的详细信息
printStackTrace();将该异常的跟踪栈信息输出到标准错误输出
printStackTrace(PrintStream s);将改异常的跟踪栈信息输出到指定输出流
getStackTrace();返回该异常的跟踪栈信息
1.5、使用finally回收资源
回收try块打开的物理资源(数据库连接,网络连接,磁盘文件等等),catch块和finally块至少出现一个,finally如果有必须放在catch之后
FileInputStream fis=null;
try{
fis=new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
return;
//system.exit(1);
}finally {
//关闭磁盘文件
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("已关闭资源");
}
注意:catch中执行了return后还会执行finally代码块
但是catch中执行了system.exit(1);后就会退出虚拟机
1.6、自动关闭资源的try语句,try中加入参数,java7后代码下:
try(BufferedReader br=new BufferedReader(new FileReader("a.txt"))){
System.out.println("try自动关闭资源");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
java9改进之后代码:
FileReader f=new FileReader("a.txt");
BufferedReader br=new BufferedReader(f);
try (br){
System.out.println("自动关闭资源");
}
1.7、使用throws声明抛出异常
思路:当前方法不知道该如何处理此类异常时,由上一级调用者处理此异常,main函数也可以使用throws,向上交给JVM处理
public static void main(String[] args) throws IOException {
FileReader f = new FileReader("a.txt");
}
1.8、catch和throw同时使用
总结以上介绍的异常处理方式有两种分别为:
(1)在出现异常的方法内捕获并处理异常,改方法的调用者将不能再次捕获该异常
(2)该方法签名中声明抛出异常,将该异常完全交给方法调用者去处理
实际应用中往往有复杂情况,需要几个方法同时协作才能处理该异常,也就是说,当出现异常时,该方法只能对部分异常进行处理,部分异常需要调用者去处理,例如:
public class AuctionTest {
private double initPrice=30.0;
public void bid(String price) throws ArithmeticException{
double d=1.0;
try{
d=Double.parseDouble(price);
}catch (Exception e){
e.printStackTrace();
throw new ArithmeticException();
}
}
public static void main(String[] args) {
AuctionTest at=new AuctionTest();
try {
at.bid("wangli");
}catch (ArithmeticException e){
System.out.println("捕获到bid抛出的异常,进行处理");
}
}
}
bid方法中catch块对异常进行处理时也抛出了异常,,会通知该方法的调用者再次处理抛出的异常。
1.9、java7增强的throw语句
在java7以前检测到e为什么异常类型就会抛出什么异常,简单粗暴,java7之后会检测e的实际类型
public class ThrowTest2 {
public static void main(String[] args) throws FileNotFoundException {
try {
FileOutputStream fileOutputStream = new FileOutputStream("1.txt");
} catch (Exception e) {
//java7在检查throw e时可能抛出异常的实际类型
//因此在此处声明抛出FileNotFoundException异常即可
e.printStackTrace();
throw e;
}
}
}
1.10、异常链
在实际应用中,常常会有分层关系,层与层之间有非常清晰的划分,上一层功能的实现又依赖于下层的API,本层得到下层的异常后不能反馈给上一层,这样会暴露信息。通常做法为:
程序先捕获原始异常,然后抛出一个新的业务异常,叫做异常转译
public void calSal() throws SalException{
try {
//业务逻辑
}catch (SQLException se){
//原始异常进行记录
//抛出新的异常
throw new salException("系统出现错误");
}
}
1.11、自定义异常类
用户自定义异常都应该继承Exception基类,自定义异常类需要提供两个构造器,一个无参,一个带一个字符串参数的构造器
public class AuctionException extends Exception {
public AuctionException() {
}
public AuctionException(String message) {
super(message);
}
}