简介:
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);
    }
}
 
                     
                    
                 
                    
                 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号