zoukankan      html  css  js  c++  java
  • 异常处理

    java中异常体系

    异常:java程序中存在某些不正常的情况。

    异常体系图:

    通过上图基本可以了解java中异常体系的分类和继承关系:

    异常体系:
    -------| Throwable 异常和错误的超类
    -----------| Errow 错误:一般是由于jvm或者硬件引发的问题,一般不会通过代码来处理。
    -----------| Exception 异常:一般通过代码来处理。

    --------------| 运行时异常:RuntimeException以及RuntimeException子类 都是属于运行时异常。如果一个方法内部抛出了一个运行时异常,那么方法上 可以声明也可以不 声明,调用者可以以处理也可以不处理。

    --------------|编译时异常: 除了运行时异常就是编译异常。如果一个方法内部抛出了一个编译时异常对象,那么方法上就必须要声明,而且调用者也必须要处理。

     为什么java编译器会如此严格要求编译时异常,对运行时异常如此宽松?

     运行时异常都是可以通过程序员良好的编程习惯去避免,所以java编译器就没有严格要求处理运行时异常。

    Throwable类

    Throwable是异常和错误的超类。

    常用方法:

      Throwabel常用的方法:
       toString() 返回当前异常对象的完整类名+病态信息。
       getMessage() 返回创建Throwable对象是传入的字符串信息。
       pintStackTrace() 打印异常的栈信息。

    代码示例如下:

     

     1 class Demo 
     2 {
     3     public static void main(String[] args) 
     4     {
     5         //Throwable类测试
     6         Throwable t = new Throwable("Throwable异常测试");
     7         String info = t.toString();
     8         System.out.println("toString函数返回值:"+info);
     9         String message = t.getMessage();
    10         System.out.println("message函数返回值:"+message);
    11         t.printStackTrace();
    12     }
    13 }
    View Code

    运行结果如下图:

     Throwable下分为异常和错误,那么如何根据异常信息来判断是错误还是异常呢?

      如果程序出现不正常的信息,信息类名以Error结尾就是错误;以Exception结尾的就是异常。

    Error:

      一般是由于jvm或者硬件引发的问题,一般不会通过代码来处理。如下面代码:

        //java虚拟机在默认的情况下只能管理64m内存。
          byte[] buf = new byte[1024*1024];

      

    异常

      一般通过代码来处理。如:除数为0的算数异常。代码如下

      int a = 0;

      int b = 10/a;

      此时jvm虚拟机就会抛出ArithmeticException异常。

    Jvm当遇到异常代码时时如何工作的呢?

      jvm运行到a/b这个语句的时候,发现b为0,除数为0在我们现实生活中是属于不正常的情况,jvm一旦发现了这种不正常的情况时候,那么jvm就会马上创建一个对应的异常对象,并且会调用这个异常对象 的printStackTrace的方法来处理。

    在开发中不可能所有异常都由jvm来抛出和处理。程序人员必须在代码中进行相应的处理。

    异常的处理方式:

      1、捕获处理。

      2、抛出处理。

    下面来看一下捕获处理:

    格式:

      try{
            可能发生异常的代码;

         }catch(捕获的异常类型 变量名){
            处理异常的代码....
         }

     注意的细节:

      1. 如果一个try块中出现了异常的代码,经过处理之后,那么try-catch块外面的代码可以正常执行。
        2. 如果一个try块中出现了异常的代码,那么在try块中出现异常的代码后面 的语句无法执行。
        3. 一个try块后面可以跟多个catch块,也就是一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获。

    测试代码如下:

     1 class Demo 
     2 {
     3     public static void main(String[] args) 
     4     {
     5         int a = 10;
     6         int b = 2;
     7         int[] arr = null;
     8         div(a,b,arr);
     9         
    10     }
    11 
    12     //除数为0的异常代码测试
    13     public static void div(int a, int b,int[] arr){
    14         int c = 0;
    15         try{
    16             c = a/b; //此处发生异常后,try块中的以后语句不执行
    17             System.out.println("数组的长度:"+ arr.length);
    18         }catch(ArithmeticException e){
    19             System.out.println("除数不能为0");
    20         }catch(NullPointerException e){
    21             System.out.println("出现了空指针异常....");
    22         }catch(Exception e){  
    23             System.out.println("捕获所有类型的异常");
    24         }
    25         System.out.println("捕获异常后,可以执行");
    26     }
    27 }
    View Code

    抛出处理

    抛出处理是通过 throw 和 throws两个关键字来实现。

    throw 与throws两个关键字:
     1. throw关键字是用于方法内部的,throws是用于方法声声明上的。
     2. throw关键字是用于方法内部抛出一个异常对象的,throws关键字是用于在方法声明上声明抛出异常类型的。
     3. throw关键字后面只能有一个异常对象,throws后面一次可以声明抛出多种类型的 异常。

    抛出处理要注意的细节:
       1. 如果一个方法内部抛出了一个编译时异常对象,那么该方法必须要声明抛出。
       2. 如果调用了一个声明抛出编译时异常的方法,那么调用者必须要处理。
       3. 如果一个方法抛出了一个异常对象,那么该方法也会马上停止(一个方法遇到了throw关键字,那么该方法就会马上停止)
       4. 在一种情况下只能抛出一种异常对象。

    测试代码如下:

     1 class Demo 
     2 {
     3     public static void main(String[] args) 
     4     {
     5         int a = 10;
     6         int b = 0;
     7         int[] arr = {1,2};
     8         try{
     9             div(a,b,arr);
    10         }catch(Exception e){
    11             System.out.println("发生了异常:"+e.getMessage());
    12         }
    13         
    14     }
    15 
    16     //除数为0的异常代码测试
    17     public static void div(int a, int b,int[] arr) throws ArithmeticException,NullPointerException{
    18         if(b==0){
    19             throw new ArithmeticException("除数不能为0");
    20         }else if(arr==null){
    21             throw new NullPointerException("数组指针为空");
    22         }
    23         int c = a/b;
    24         System.out.println("数组的长度是:"+arr.length);
    25         System.out.println("捕获异常后,可以执行");
    26     }
    27 }
    View Code

    何时使用抛出处理?何时捕获处理?原则是什么呢?

      如果需要通知到调用者,代码出现了问题,此时就需要使用抛出处理。

      如果代码时直接和用户打交道,遇到异常时就不要抛出,因为用户不会处理异常,此时就需要使用捕获处理了。

    自定义异常类

    sun提供了很多的异常类给我们用于描述程序中各种的不正常情况,但是sun 给我提供异常类还不足以描述我们现实生活中所有不正常情况,那么这时候我们就需要自定义异常类。

    自定义异常类的格式:

      自定义一个类继承Exception。

    下面通过一个例子来理解,需求如下:模拟QQ登录时的情况,当有网络是正常登录,没有网络的时候抛出没有网络的异常信息。

    代码如下:

     1 //自定义没有网络的异常类
     2 class NoNetWorkException extends Exception{
     3     public NoNetWorkException(String message){
     4         super(message);
     5     }
     6 }
     7 
     8 class Demo 
     9 {
    10     public static void main(String[] args) 
    11     {
    12         String ip = "192.168.1.254";
    13         ip = null;
    14         try{
    15             loginQQ(ip);
    16         }catch(NoNetWorkException e){
    17             System.out.println("异常信息:"+e.getMessage());
    18         }
    19     }
    20 
    21     public static void loginQQ(String ip)throws NoNetWorkException{
    22         if (ip==null)
    23         {
    24             throw new NoNetWorkException("网络连接失败");
    25         }
    26         System.out.println("登录成功");
    27     }
    28 
    29 }
    View Code

    finally 块

    finally块的使用前提是必须要存在try块才能使用。

    finally块的代码在任何情况下都会执行的(比如return和throw关键字后),除了jvm退出的情况。

    finally非常适合做资源释放的工作,这样子可以保证资源文件在任何情况下都 会被释放。

    使用代码示例如下:

     1 //读取文件操作
     2 import java.io.*;
     3 class Demo 
     4 {
     5     public static void main(String[] args) 
     6     {
     7         FileReader fileReader = null;
     8         try{
     9             //获取目标文件
    10             File file = new File("F:\test.txt");
    11             //建立数据通道
    12             fileReader = new FileReader(file);
    13             //读取文件
    14             char[] buffer = new char[1024];
    15             int lenght = 0;
    16             lenght = fileReader.read(buffer);
    17             System.out.println("读取到的内容:"+new String(buffer,0,lenght));
    18         }catch(IOException e){
    19             System.out.println("读取文件失败");
    20         }finally{
    21             try{
    22                 fileReader.close();
    23                 System.out.println("释放资源文件成功");
    24             }catch(Exception e){
    25                 System.out.println("释放资源文件失败");
    26             }
    27         }
    28     }
    29 }
    View Code

    综上所述try块的使用方式有以下三种方式:

    第一种: 比较适用于有异常要处理,但是没有资源要释放的。
       try{

         可能发生异常的代码
     
       }catch(捕获的异常类型 变量名){
          处理异常的代码
       }

    第二种:比较适用于既有异常要处理又要释放资源的代码。
      
      try{

         可能发生异常的代码
     
       }catch(捕获的异常类型 变量名){
          处理异常的代码
       }finally{ 
          释放资源的代码;
       }

    第三种: 比较适用于内部抛出的是运行时异常,并且有资源要被释放。(运行时异常可以捕获也可以不捕获)
         try{

         可能发生异常的代码
     
       }finally{ 
          释放资源的代码;
       }

  • 相关阅读:
    关于钩子函数的详细解答:
    Vue实现回到顶部
    Vue实现Rate组件(星星评分)
    Vue-router 路由模式
    javascript中实现跨域的方式
    Promise
    webpack使用
    小程序登录
    api工厂的sdk的使用
    面试题划“重点”
  • 原文地址:https://www.cnblogs.com/nicker/p/6159519.html
Copyright © 2011-2022 走看看