为什么要进行异常处理::
因为程序员在写代码时,不可能列举出所有的错误情况,而且在进行错误的列举时,也容易出现代码错误处理代码和业务实现代码混乱的情况。而使用异常处理机制,可以让程序具有极好的容错性,让程序更加健壮。当程序出现意外情形时,系统会自动生成一个Exception对象来通知程序,从而实现将“业务功能实现代码”和“错误处理代码”分离开。
1、异常处理通常包括的关键字是try catch finally throw throws五个关键字,
(1)try里放置的是可能发生异常的代码块
(2)catch后对应异常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块。
(3)多个catch后面还可以跟一个finally块,finally用于回收try里打开的物理资源,异常机制会保证finally块总是被执行。
(4)throws用于声明该方法可能抛出的异常
(5)throw可以单独作为语句使用,抛出一个具体的异常对象
try和catch后面紧跟的{}是不能是省略的。
2、分类
java中把所有非正常情况分为两种:异常和错误,二者都是继承自Throwable类
(1)错误(Error)一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态连接失败等,这种错误无法恢复或者不可能捕获,将导致程序中断。
(2)捕获多种类型的异常时,异常变量会有final修饰,但是捕获一种类型的异常时,异常变量不会有final修饰
try{}
catch(IndexOutOfBoundsException | NumberFormatException | ArithmeticException ie){
System.out.println("出现异常");
ie=new ArithmeticException("test");//会出现错误,因为捕获多异常时,异常变量默认的是final修饰,
}
cathc(Exception e){
e=new RuntimeException("fd");//是正确的,因为单个异常捕获时,异常变量没有用final修饰
}
3、访问异常信息
如果程序需要在catch块中访问异常对象的相关信息,则可以通过访问catch块的后异常形参来获得。
所有的异常对象都包括的方法:
(1)getMessage():返回该异常的详细文字描述
(2)printStackTrace():将该异常的跟踪栈信息输出到标准错误输出
java.io.FileNotFoundException: a.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at test1.aaa.main(aaa.java:11)
(3)peintStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流
(4)getStackTrace():返回该异常的跟踪栈信息
4、finally回收资源:有些时候,程序在try块中打开的一些物理资源,比如数据库连接,网络连接和磁盘文件等,这些物理资源都必须显示回收。
为什么不在try或者catch进行资源回收?
因为(1)如果在try中执行,某一个语句出现了异常,则该语句后的其他异常语句将得不到处理;(2)如果在catch中进行资源回收,可能会出现catch有可能得不到执行,这将导致不能进行资源回收。但是当try后面出现()时,可以在()里面进行显示的资源关闭,为了保证try语句可以正常关闭资源,这些资源实现类必须实现AutoCloseable或者Closeable接口。
为了保证一定能够进行资源回收,使用finally块,不管try代码块中是否出现异常,也不管哪一个catch块被执行,甚至在try块或者catch块中执行了return语句,finally块总会被执行。
不管是try还是catch中执行了return语句,finally中的语句还是会被执行,但是如果在try或者catch中出现System.exit(1)语句时,就会退出虚拟机,那么finally也将失去执行的机会。一旦在finally中执行了return或者throws语句,将会导致try,catch中的return ,throw语句失效。
5、异常处理顺序
当java执行try,catch块时遇到return 或throw语句,这两个语句就会导致该方法立即结束,但是系统执行这两个语句时,并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序就立即执行return或者throws语句块,否则就先执行完finally里面的语句块,在跳回来执行try catch中的return 或者throws语句块。如果finally中含有return或者throws那么系统就不会跳回去执行try或者catch中的任何代码块,应尽量避免在finally中使用return或者throws语句块,因为容易出现各种奇怪的情况。
6、Checked异常和Runtime异常
java中的异常被分为两大类:Checked(只有java中含有该异常类型)和Runtime(运行时异常),
对于checked异常的处理方式有两种:
(1)当前方法明确知道会出现什么异常
(2)当前方法不能确定会出现什么类型的异常
7、使用throws类抛出异常,
思路是:当前方法不知道如何处理这种类型的异常,那么该异常应该由上一级调用者处理;如果main方法也不知道如何处理这种异常,也可以使用throws声明抛出异常,该异常有JVM处理,那么JVM处理异常的方法是:打印异常的跟踪栈信息,并终止程序运行,这就是前面程序遇到异常后自动结束的原因。
throws声明抛出只能在该方法签名中使用.
对于checked类型的异常,当涉及到方法重写时,应该遵循以下 规则:
(1)子类方法声明抛出的异常类型应该比父类方法声明抛出的异常类型小或者相同
(2)子类方法中抛出的异常不应该比父类方法中抛出的异常多。
throws是系统自动抛出异常,throw是程序自行抛出的异常。
(1)throw抛出的异常是checked异常,则该throw语句要么处于try块里,显式捕获该异常,要么放在一个带有throws声明抛出的方法中,即把该异常交给该方法的调用者处理。
(2)如果throw抛出的异常是Runtime异常,则该语句无须放在try块里,可无须放在带throws声明抛出的方法中。
7、自定义异常类
用户自定义的异常类都应该继承Exception基类,如果希望自定义Runtime异常,则应该继承RuntimeException基类。定义异常类通常需要定义两个构造器,一个无参构造器,一个带有字符串构造器,该字符串将作为该异常对象的描述信息(也就是异常对象的getMessage()方法的返回值)
public class AuctionException extends Exception{
public AuctionException(){}
public AuctionException(String msg){
super(msg);
}
}