Java异常处理机制(经典)

一、概述

         异常处理已经成为衡量一门语言是否成熟的标准之一。目前主流的编程语言如,C++、C#、Java都提供了异常处理机制。增加异常处理机制使程序有更好的兼容性、健壮性。

         异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C开始,也许已用if...else...来控制异常了,也许是自发的,然而这种控制异常痛苦,同一个异常或者错误如果多个地方出现,都要做相同处理,感觉相当麻烦!

  Java语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,所有的异常都可以用一个类型来表示,不同类型的异常对应不同的子类异常(这里的异常包括错误概念),定义异常处理的规范,在1.4版本以后增加了异常链机制,从而便于跟踪异常!

二、Throwable类

 先从Java异常类继承关系  最顶级Throwable类说起:

1.Throwable 可抛出的(是Object的子类)。
2.Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。 

3.两个子类的实例,Error 和 Exception,通常用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。

4.Throwable类中的常用方法
注意:catch关键字后面括号中的Exception类型的参数e。Exception就是try代码块传递给catch代码块的变量类型,e就是变量名。catch代码块中语句"e.getMessage();"用于输出错误性质。通常异常处理常用3个函数来获取异常的有关信息:


     getCause():返回抛出异常的原因。如果 cause 不存在或未知,则返回 null。

  printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。

     public String getMessage() 返回此 throwable 的详细消息字符串。

     public void printStackTrace()将此 throwable 及其追踪输出至标准错误流。此方法将此Throwable 对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。
     public void printStackTrace(PrintWriter s)将此 throwable 及其追踪输出到指定的 PrintWriter。


  5.Error和Exception区别
  Error  是不可修复、不可捕获的、致命的;一般是与编译器相关的问题,如系统崩溃、虚拟机错误、动态链接库失败等。 Java虚拟机(JVM)一般会选择线程终止
  Exception 是可以避免的;java.lang.Exception类是Java中所有异常的直接或间接父类。即Exception类是所有异常的根类。
注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。
Java中的异常分为两大类:
  1.Checked Exception(检查型异常)
  2.Unchecked Exception(Runtime Exception)非可检查型

  1、检查型异常:是编译器要求必须处置的异常,一般 简单的可在编辑时检查出,如拼写错误、包没有导入、括号匹配错误等,这些检查一般的IDE开发工具就能帮我们检测出来。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。如读写文件文件找不到、网络连接失败[事先无法判知],需要用Try 异常处理语句  或抛出声明。

  2、非可检型查型(运行时异常):都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

      运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。但运行时Over。
常见的7类
1、算数异常:针对于除法运算分母为0时
2、空指针异常:对象未初始化时
3、数组下表越界异常
4、数组下标为负异常:数组下标为负数
5、字符串下标越界异常
6、数字格式异常:如将字符串"123a"转化为int 型,格式异常
7、类型转化异常
    java.lang.ArrayIndexOutOfBoundsException 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
    java.lang.ArithmeticException算术条件异常。譬如:整数除零等。
    java.lang.NullPointerException空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方
    java.lang.NegativeArraySizeException  数组长度为负异常
    StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
    ClassCastException    类型转换异常类

三、异常处理机制

        在 Java 应用程序中,异常处理机制为:1.捕获异常,2.抛出异常。
        1、抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交给运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。通常是一级一级,向外抛出,异常交给调用它的对象处理。
        2、捕获异常:采用try...catch语句,在方法调用处捕获异常;在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

四、Java7 提供多异常捕获

在Java7之前,一个catch{}块只能捕获一个异常,Java7开始,一个catch{}可以捕获多个异常,如catch (ArithmeticException e | NullPointerException e1)

try-catch-finally 结构:

try
    {
         // 可能发生异常的代码
        // 如果发生了异常,那么异常之后的代码都不会被执行
    }
    catch (Exception e)
    {
        // 异常处理代码
    }
    finally
    {
        // 不管有没有发生异常,finally语句块都会被执行
//常在此关闭物理资源,如连接的数据库、读取的文件等
//面试常考---即使方法已在前面的catch{}中return,finally语句块也会被执行
    }
       Java异常处理通过5个关键字try、catch、throw、throws、finally进行管理和实现。基本过程是用try语句块包住要监视的语句[可能出现异常的代码块],如果在try语句块内出现异常,则异常会被抛出,代码在catch语句块中可以捕获到这个异常并做处理;还有以部分系统生成的异常在Java运行时自动抛出。也可以通过throws关键字在方法上声明该方法要抛出异常,然后在方法内部通过throw抛出异常对象。finally语句块会在方法执行。


try-catch-finally 规则(异常处理语句的语法规则):
1)  必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。
2) 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
3) catch 块与相应的异常类的类型相关。
4) 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块
5) 可嵌套 try-catch-finally 结构。
6) 在 try-catch-finally 结构中,可重新抛出异常。
7) 除了下列情况,总将执行 finally 做为结束:JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击。


抛出异常---见下面的  自定义异常  一起讲解。

自定义异常
  所谓自定义异常,通常就是自己定义的一个类,继承了Exception类或者它的子类。因为异常必须直接或者间接地继承自Exception类。

  通常情况下,会直接继承自Exception类,一般不会继承某个运行时的异常类。

  自定义异常可以用于处理用户登录错误,用户输入错误提示等。

  自定义异常的例子:

  自定义一个异常类型: 

public class MyException extends Exception
{
    public MyException()
    {
        super();
    }    
    public MyException(String message)
    {
        super(message);
    }
}

一种异常处理方式:抛出异常;不断一级一级向外抛出,异常交给调用它的对象处理

 public void method(String str) throws MyException          //方法抛出异常
    {
        if(null == str)
        {
            throw new MyException("输入的密码不能为null!");//自定义异常
        }
        else
        {
            System.out.println(str);
        }
    }
//在main方法中调用此方法时,main方法也需throws MyException,继续向外抛出异常
  public static void main(String[] args) throws MyException
 但main方法抛出异常,交给虚拟机处理,结果就是----如果main方法有异常抛出,Java虚拟机直接终止程序

另一种异常处理方式:采用try...catch语句,在方法调用处捕获异常
public static void main(String[] args)
    {
        try
        {
            MyException  test = new MyException();
            test.method(null);
        }
        catch (MyException e)
        {
            e.printStackTrace();
        }    
        finally
        {
            System.out.println("MyException处理完毕");
        }
    }


throws抛出异常:是方法 抛出异常;
如: public void method(String str) throws MyException          //方法抛出异常

throw抛出异常:是出现在函数体中
throw总是出现在函数体中,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。如:throw new MyException("输入的密码不能为null!");

注意:

1.异常捕获时,一定要记住,先捕获小异常,再捕获大异常。也就是说---需要将父类型的catch块放到子类型的catch块之后,这样才能保证后续的catch块可能被执行,否则子类型的catch块将永远无法到达,Java编译器会报错。如果异常类型是独立的,那么它们的前后顺序没有要求。
2.一个try后面可以跟多个catch,但不管多少个,最多只会有一个catch块被执行。也就是说---一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会。但finally{}语句块一定执行。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值