Java异常处理机制

异常处理机制:

1.使用try...catch捕获异常

public void update(){
        session=sessionFactory.openSession();
        Transaction transaction=session.beginTransaction();
        try{
            Dage dage=session.get(Dage.class,1);
            dage.setName("DAGE");

            session.update(dage);
            transaction.commit();
        }catch (Exception e){
            transaction.rollback();
            e.printStackTrace();
        }finally {
            session.close();
        }
    }

 

  • 抛出异常:如果执行try块里的业务逻辑代码出现异常,系统会自动生成一个异常对象,该异常对象被提交给Java运行时环境,这个过程被称为抛出异常;
  • 捕获异常:当Java运行时环境收到异常对象时,会寻找到能处理该异常对象的catcah块,如果找到合适的catch块并把该异常对象交给该catch块处理,这个过程被称为捕获异常;如果Java运行时环境找不到捕获异常的catch块,则运行时环境终止,Java程序退出;

不管程序代码块是否处于try块中,甚至包括catch块中代码,只要执行该代码块时出现了异常,系统都会自动生成一个异常对象。

2.异常类的继承体系:

Java把所有非正常情况分为两种:异常(Exception)和错误(Error),都继承Throwable父类;

  • Error:一般是指虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象;
  • Exception:异常是另外一个非常重要的异常子类,它规定的异常是程序本身可以处理的异常,异常和错误的区别是,异常可以被处理而错误不能;

3.访问异常信息:

 如果程序需要在catch块中访问异常对象的相关信息,可以通过调用catch后异常形参的方法来获得,当Java运行时决定调用某个catch块来处理该异常对象时,会将该异常对象赋给catch块后的异常参数,程序就可以通过该参数来获得该异常的相关信息;所有异常对象都包含如下几个方法:

  • getMessage():返回该异常的详细描述字符串;
  • printStackTrace():将该异常的跟踪栈信息输出到标准错误输出;
  • printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流;
  • getStackTrace():返回该异常的跟踪栈信息;
public void t(){
        try {
            FileInputStream fis=new FileInputStream("a.txt");
        }catch (Exception e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }

4.使用finally回收资源

  这些物理资源包括(数据库连接、网络连接和磁盘文件),这些都需要显示的回收;Java的垃圾回收机制不会回收任何物理资源,垃圾回收机制只能回收堆内存中对象所占有的内存;

finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。

若在finally块中也有return语句时,则系统不会调回去执行try、catch块里的任何代码;

Checked异常和Runtime异常:

异常被分为两大类:Checked异常和Runtime异常(运行时异常):

  • Checked Exception:可检查的异常,这是编码时非常常用的,所有checked exception都是需要在代码中处理的。它们的发生是可以预测的,正常的一种情况,可以合理的处理。比如IOException,或者一些自定义的异常。除了RuntimeException及其子类以外,都是checked exception;这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
  • Unchecked Exception:RuntimeException及其子类都是unchecked exception。比如NPE空指针异常,除数为0的算数异常ArithmeticException等等,这种异常是运行时发生,无法预先捕捉处理的。Error也是unchecked exception,也是无法预先处理的;

对于Checked异常的处理方式有两种:

  • 当前方法明确知道如何处理该异常,程序应该使用try...catch块来捕获该异常,然后在对应的catch块中修补该异常;
  • 当前方法不知道如何处理该异常,应该在定义该方法时声明抛出该异常;

使用throws声明抛出异常:

  使用throws声明抛出异常的思路是:当前方法不知道应该如何处理这种类型,该异常由它的上一级调用者处理,如果main方法也不知道应该如何处理这种类型的异常,也可以使用throws声明抛出异常,该异常交给JVM处理。JVM对异常的处理方法是:打印异常跟踪信息,并终止程序运行,

  如果某段代码中调用了一个带throws声明的方法,该方法声明抛出了Checked异常,这表明该方法希望它的调用者来处理该异常,即要么捕获要么抛出;

public void t() throws FileNotFoundException {
        t1();
        try {
            FileInputStream fis=new FileInputStream("a.txt");
        }catch (Exception e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    public void t1() throws FileNotFoundException {
        FileInputStream fis=new FileInputStream("a.txt");
    }

  使用throws声明抛出异常时:子类方法中抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相等,子类不允许比父类声明抛出更多的异常;

Throws抛出异常的规则:

    1) 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。

    2)必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误

    3)仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。

    4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

使用throw抛出异常:

  当程序出现错误的时,系统会自动抛出异常;除此之外,Java也允许程序自动抛出异常,自行抛出异常使用throw语句完成;throw语句抛出的不是异常类,而是一个异常实例且每次只能抛出一个异常实例;

  当Java运行时接受到用户自行抛出的异常时,一样会终止当前的执行流,调到对应的catch块中,由该catch块来处理该异常;也就是说,不管是系统自动抛出的异常,还是程序员手动抛出的异常,Java运行时环境对异常的处理没有任何差别。

   如果throw语句抛出的异常是Checked异常,则该throw语句要么在try块里,显示捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给调用者处理;若是Runtime异常,则该语句无需放在try块里,也无须放在带throws声明抛出的方法中;程序即可以显示的用try...catch来捕获,并处理该异常,也可以完全不理会该异常,把该异常交给该方法的调用者处理;

自定义异常类:

  用户自定义异常都应该继承Exception基类(或Runtime),定义异常类时通常需要提供两种构造器:一个无参数的构造器,另一个是带一个字符串的构造器,这个字符串将作为该异常对象的详细说明(即getMessage方法的返回值)

package exception;

public class AuctionException extends Exception {
    public AuctionException(){}
    public AuctionException(String msg){
        super(msg);
    }
}

catch和throw同时使用:

以上的异常处理方式有两种:

  • 在出现异常的方法内捕获并处理异常,该方法的调用者不能再次捕获异常;
  • 该方法签名中声明抛出异常,将该异常完全交给方法调用者处理;

实际中则复杂一点:当一个异常出现时,单靠某个方法无法完全处理该异常,必须由几个方法的协作才可以完全处理该异常;即异常出现在当前方法中,程序只对异常进行部分处理,还有些处理需要在该方法的调用者中才能完成,所以应该再次抛出异常,让调用者捕获;

package exception;

public class TestAuction {
    private double initPrice=10.0;
    public void bid(String bidPrice)throws AuctionException{
        double d=0.0;
        try {
            d=Double.parseDouble(bidPrice);
        }catch (Exception e){
            e.printStackTrace();
            throw new AuctionException("必须是数值");
        }
    }

    public static void main(String[] args) {
        TestAuction testAuction=new TestAuction();
        try{
            testAuction.bid("qww");
        }catch (AuctionException a){
            System.out.println(a.getMessage());
        }
    }
}

异常链:

  • 常常会再捕获一个异常后抛出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链。
  • 在JDK1.4以前,程序员必须自己编写代码来保存原始异常信息,
  • 现在所有Throwable的子类子构造器中都可以接受一个cause对象作为参数,这个cause就异常原由,代表着原始异常,即使在当前位置创建并抛出行的异常,也可以通过这个cause追踪到异常最初发生的位置。
  • Throwable类及其所有的子类都提供了带cause参数的构造器,其他的异常类就只有通过initCause()来设置cause;

应用场景:异常需要封装,但是仅仅封装还是不够的,还需要传递异常。一个系统的友好型的标识,友好的界面功能是一方面,另一方面就是系统出现非预期的情况的处理方式了。

public class AuctionException extends Exception {
    public AuctionException(){}
    public AuctionException(String msg){
        super(msg);
    }
    public AuctionException(Throwable t){
        super(t);
    }
}
public class TestAuction {
    private double initPrice=10.0;
    public void bid(String bidPrice)throws AuctionException{
        double d=0.0;
        try {
            d=Double.parseDouble(bidPrice);
        }catch (Exception e){
            e.printStackTrace();
            //throw new AuctionException("必须是数值");
            throw new AuctionException(e);
        }
    }

    public static void main(String[] args) {
        TestAuction testAuction=new TestAuction();
        try{
            testAuction.bid("qww");
        }catch (AuctionException a){
            System.out.println(a.getMessage());
        }
    }
}

小结:

  • try...catch:对于觉得会有异常抛出的程序块,用try{}包住,然后用catch来捕获异常,并在catch中对异常做自行处理;
  • throw:由于try...catch只能获取程序运行时引发的异常,而throw语句可以引发明确的异常,程序运行到throw语句就停止,不会执行后面的程序;
  • throws:如果一个方法会有异常,但你并不想处理这个异常,就在方法名后面用throws,因此该异常就会被抛出,谁调用了这个方法谁就要处理这个异常,或者继续向父类抛出;
  • throw和throws的区别:
  1. throw在语句中,throws在方法后面;
  2. throw只抛出一个异常实例,throws可以抛出多个异常类;
  3. 当抛出的是Checked异常时,throw需要和try...catch或者throws结合使用;
  4. 当抛出的是Runtime异常时可以单独使用;
  5. throw是明确抛出异常,throws是有可能抛出这些异常;

常见异常:

runtimeException子类:

        1、 java.lang.ArrayIndexOutOfBoundsException
        数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
        2、java.lang.ArithmeticException
        算术条件异常。譬如:整数除零等。
        3、java.lang.NullPointerException
        空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
        4、java.lang.ClassNotFoundException
        找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

       5、java.lang.NegativeArraySizeException  数组长度为负异常

       6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常

       7、java.lang.SecurityException 安全性异常

       8、java.lang.IllegalArgumentException 非法参数异常

IOException:

    IOException:操作输入流和输出流时可能出现的异常。

    EOFException   文件已结束异常

    FileNotFoundException   文件未找到异常

其他:

    ClassCastException    类型转换异常类

    ArrayStoreException  数组中包含不兼容的值抛出的异常

    SQLException   操作数据库异常类

    NoSuchFieldException   字段未找到异常

    NoSuchMethodException   方法未找到抛出的异常

    NumberFormatException    字符串转换为数字抛出的异常

    StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常

    IllegalAccessException  不允许访问某类异常

    InstantiationException  当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream答案

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值