zoukankan      html  css  js  c++  java
  • Java基础11—异常处理

    异常处理


    参考资料:《Java从入门到精通》/明日科技编著. 4版. 北京:清华大学出版社,2016

    一、异常概述

    异常是一个在程序执行过程中发生的事件,它中断了正在执行程序的正常指令流。有很多异常的例子,如空指针、数组溢出等。

    Java是一门面向对象的编程语言,因此,异常在Java语言中也是作为类的实例的形式出现的。当某一方法发生错误时,这个方法会创建一个对象,并且把它传递给正在运行的系统,这个对象就是异常对象。

    通过异常处理机制,可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程的同时,在其他地方处理异常。

    二、处理程序异常错误

    • 为了保证程序的正常执行,需要对发生的异常进行相应的处理。
    • 在Java中,如果某个方法抛出异常,既可以在当前方法中进捕捉,然后进行处理,也可以将异常向上抛出,由方法调用者来处理。

    下面介绍Java中捕捉异常的方法:

    1、错误

    • 异常产生后,如果不做任何处理,程序就会被终止
    public class Demo1 {
        public static void main(String[] args) {
            String str1 = "23";
            String str2 = "ab";
            
            int age1 = Integer.parseInt(str1);   //将数字型字符串转换成int型
            System.out.println(str1);
    
            int age2 = Integer.parseInt(str2);   //将数字型字符串转换成int型
            System.out.println(str2);
        }
    }
    
    运行结果:
    23
    Exception in thread "main" java.lang.NumberFormatException: For input string: "ab"
    	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    	at java.lang.Integer.parseInt(Integer.java:580)
    	at java.lang.Integer.parseInt(Integer.java:615)
    	at com.demo_5_16.Demo1.main(Demo1.java:10)
    

    从上述代码的执行结果可以看出,报出了NumberFormatException(字符串转数字)的异常,str1变量的值已经输出,str2变量的值没有输出,可知程序由于异常而终止。

    2、捕捉异常

    Java的异常捕捉结构由trycatchfinally组成;

    • try语句块存放的是可能发生异常的Java语句;
    • catch语句在try语句块之后,用来激发被捕获的异常;
    • finallly语句块是异常处理结构的最后执行部分,无论try语句块的代码如何退出,都将执行finally语句块。

    语法如下:

    try {
        //代码块
    }
    catch (ExceptionType1 e) {
        //对 ExceptionType1的处理
    }
    catch (ExceptionType2 e) {
        //对 ExceptionType2的处理
    }
    ...
    ...
    finally {
        //代码块
    }
    

    由此可知,异常处理器大致分为try-catch语句块和finally语句块。

    (1)try-catch语句块

    public class Demo1 {
        public static void main(String[] args) {
            try {
                String str1 = "23";
                String str2 = "ab";
    
                int age1 = Integer.parseInt(str1);   //字符型转换成int型
                System.out.println(str1);
    
                int age2 = Integer.parseInt(str2);   //字符型转换成int型
                System.out.println(str2);
                
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println("程序结束");
        }
    }
    
    运行结果:
    23
    程序结束
    java.lang.NumberFormatException: For input string: "ab"
    	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    	at java.lang.Integer.parseInt(Integer.java:580)
    	at java.lang.Integer.parseInt(Integer.java:615)
    	at com.demo_5_16.Demo1.main(Demo1.java:12)
    

    从上述代码的运行结果可知,程序输出了最后的提示信息,没有因为异常而终止。

    使用try-catch语句块进行异常处理过程:

    1. 当try语句块中的语句发生异常时,程序就会调转到catch代码块中执行;
    2. 执行完catch代码后,将继续执行catch代码块后面的代码,而不会执行try代码块中发生异常语句后面的代码。

    其中,Exception是代码块传递给catch代码块的变量类型e是变量名。通常,异常处理常用的3个函数来获取异常的有关信息。

    • getMessage() :输出错误的性质;
    • toString() :给出异常的类型与性质;
    • printStackTrace() :指出异常的类型、性质、栈层次以及出现在程序中的位置。

    (2)finally语句块

    完整的异常处理语句一定要包括finally语句块,无论程序中有无异常的发生,并且无论之前的try-catch语句是否顺利执行完毕,都会执行finally语句。

    在4种情况下finally语句不会执行:

    1. 在finally语句块中出现了异常;
    2. 在前面的代码中使用了System.exit()退出程序;
    3. 程序所在的线程死亡;
    4. 关闭CPU。

    四、自定义异常

    使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户只需要继承Exception类即可自定义异常类。

    在程序中使用自定义异常类,大可分为以下几个步骤:

    1. 创建自定义异常类;
    2. 在方法中通过throw关键字抛出异常对象;
    3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句块捕捉异常并处理,否则在方法的声明处通过throw关键字指明要抛出给方法调用者的异常,继续进行下一步;
    4. 在出现异常方法的调用者中捕获并处理异常。
    /*
    *通过继承Exception类,自定义一个异常类 
    */
    class MyException extends Exception {
        //自定义异常类的构造方法
        public MyException (String ErrorMessage){
            //调用父类的构造方法
            super(ErrorMessage);
        }
    }
    
    public class Tran {
        //定义方法,并使用throws关键字指明要抛出的异常的类型,即异常类型为MyException类
        static int avg(int n1, int n2) throws MyException {
            //判断参数是否满足指定的条件
            if (n1 < 0 || n2 < 0){
                //抛出异常对象
                throw new MyException("不可以为负数");
            }
            //判断参数是否满足指定的条件
            if (n1 > 100 || n2 > 100){
                //抛出异常对象
                throw new MyException("数字过大");
            }
            //若参数正常,则返回结果
            return (n1 + n2) / 2;
        }
    
        public static void main(String[] args) {
            //使用try-catch语句块捕捉异常
            try{
                int result = Tran.avg(112,-34);   //调用avg()静态方法
                System.out.println(result);
                
            }catch (MyException e){   //处理捕获到的异常,相当于 MyException e = new MyException("不可以为负数");
            //当然,这里写成"Exception e"也是没有问题的,因为MyException继承了Exception类
                System.out.println(e);   //输出异常信息
                // e.printStackTrace();   //也可以使用该语句打印异常信息
            }
        }
    }
    
    运行结果:
    com.demo_5_17.MyException: 不可以为负数
    

    五、在方法中抛出异常

    若某个方法中可能会发生异常,但是不想在当前方法中处理异常,则可以使用throws、throw关键字在方法中将异常抛出。

    1、使用throw关键字抛出异常

    throws关键字通常用在声明方法时,用来指定方法可能抛出的异常,多个异常可以用逗号分隔。

    public class Shoot {
        //定义方法,并指定抛出异常的类型
        public void pop() throws NegativeArraySizeException {
            int arr[] = new int[-3];   //故意制造一个异常,即指定数组长度为-3
        }
    
        public static void main(String[] args) {
            try {
                Shoot shoot = new Shoot();
                shoot.pop();
            }catch (NegativeArraySizeException e){
                System.out.println("异常类型为:" + e);
            }
        }
    }
    
    运行结果:
    异常类型为:java.lang.NegativeArraySizeException
    

    上述代码中,使用throws关键字将异常抛给方法的调用者。使用throw关键字将异常抛给上一级后,如果不想处理该异常,可以继续往上抛,但最终要有能处理该异常的代码。

    2、使用throw关键字抛出异常

    • throw关键字通常用于方法体中,并且抛出一组异常对象
    • 程序在执行到throw语句时立即终止,它后面的语句都不执行;
    • 通过throw抛出异常后,如果想在上一级代码中捕获并处理异常,则需要在抛出异常的方法中使用throws关键字在方法声明时指明要抛出的异常。
    • 如果要捕获throw抛出的异常,则必须使用try-catch语句。
    • throw通常用来抛出用户自定义的异常。
    /*
    *自定义异常类
    */
    class MyException2 extends Exception {
        String message;
        public MyException2(String message){
            this.message = message;
        }
        public String getMessage(){
            return this.message;
        }
    }
    
    public class Captor {
        /*
        * 在声明方法时,指定抛出异常类型
        * 可以指定多个可能抛出的异常类型
        */
       public int div(int n1, int n2) throws MyException2, ArithmeticException{
            if (n2 < 0){
                throw new MyException2("除数不能是负数");   //抛出异常对象
            }
            if (n2 == 0){
                throw new ArithmeticException();   //抛出异常对象
            }
            return n1 / n2;
        }
    
        public static void main(String[] args) {
            try{
                Captor captor = new Captor();
                int result = captor.div(24,-3);
            }catch (MyException2 e){
                //若抛出的异常对象为MyException2类型,则执行该代码块
                System.out.println(e.getMessage());
            }catch (ArithmeticException e){
                //若抛出的异常对象为ArithmeticException类型,则执行该代码块
                System.out.println("抛出算术异常");
            }catch (Exception e) {
                //如果还有其他类型,则使用Exception来捕捉
                System.out.println("抛出其他异常");
            }
        }
    }
    
    运行结果:
    除数不能是负数
    

    上述代码中使用了多个catch语句进行捕捉异常:

    • 如果调用div(24, -3)方法,将发生MyException异常,程序调转到catch (MyException2 e)代码块中执行。
    • 如果调用div(24, 0)方法,将发生ArithmeticException异常,程序调转到catch (ArithmeticException e)代码块中执行。
    • 如果还有其他类型异常发生,则使用catch (Exception e)捕捉异常。

    由于Exception是所有异常类的父类,如果将catch (Exception e)代码块放置在其他两个代码块的前面,后面的代码块将永远得不到执行,也就没有什么意义了,因此catch语句的顺序不可随意调换。

    六、运行时异常

    • RuntimeException异常是程序运行过程中产生的异常。
    • Java类库的每个包中都定义了异常类,所有的这些类都是Throwable类的子类。
    • Throwable类派生出了两个子类,分别是Exception类和Error类。
    • Error类及其子类用来描述Java运行系统中的内部错误以及资源耗尽的错误,这类错误比较严重
    • Exception类称为非致命性错误类,可以通过捕捉处理使程序继续执行。
    • Exception类又根据错误发生的原因分为RuntimeException异常非RuntimeException异常

    Java中提供了常见的RuntimeException异常,这些异常可以通过try-catch语句捕获,如下表所示:

    种类 说明
    NullPointerException 空指针异常
    ArrayIndexOutOfBoundsException 数组下标越界异常
    ArithmeticException 算术异常
    ArrayStoreException 数组中包含不兼容的值抛出的异常
    IllegalArgumentException 非法参数异常
    SecurityException 安全性异常
    NegativeArraySizeException 数组长度为负数异常

    七、异常的使用原则

    • Java异常强制用户去考虑程序的健壮性和安全性。
    • 异常的处理不应该用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应的处理。

    编写代码处理某个方法可能出现的异常时,可遵守以下几条原则

    1. 在当前方法声明中使用try-catch语句捕捉异常;
    2. 一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或该异常的子类;
    3. 如果父类抛出多个异常,则覆盖方法必须抛出那些异常的一个子集,不能抛出新异常。
  • 相关阅读:
    Python流程控制
    Python 迭代器和列表解析
    Python 文件对象
    TF-IDF介绍
    hexo博客更换主题
    学习笔记—MapReduce
    Mac下Anaconda的安装和使用
    Flume的介绍和简单操作
    hexo+github搭建个人博客
    Hbase的安装和基本使用
  • 原文地址:https://www.cnblogs.com/xuliang-daydayup/p/12905668.html
Copyright © 2011-2022 走看看