首页 > 代码库 > Java——异常

Java——异常

 

  Java 的异常机制主要依赖于try 、catch 、finally 、throw 和 throws 五个关键字,其中 try 关键字后紧跟一个花括号括起来的代码块(花括号不能省略),简称 try 块,它里面放置可能引发异常代码。 catch 后对应异常类型和一个代码块,用于表明该 catch 块用于处理这种类型代码块 。 多个 catch 块后还可以跟一个 finally 块,finally块用于回收在 try 块里打开的物理资源,异常机制会保证 finally 块总会被执行。 throws 关键字主要在方法签名中使用,用于声明该方法可能抛出的异常;而 throw 用于抛出一个实际的异常, throw 可以单独作为语句使用,抛出一个具体异常对象。

演示程序中异常:

public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1=input.nextInt();
        System.out.println("请输入被除数:");
        int num2= input.nextInt();
        System.out.println(String.format("%d /%d =%d", num1,num2,num1/num2));
        System.out.println("感谢使用本程序!");

    }

  在正常情况下,用户会按照系统的提示输入整数,除数不为 0 ,运行结果如下:

    技术分享

但是用户没按照要求进行输入,如被除数输入了“B”,则程序运行时将会发生异常,运行如下:

技术分享

或者输入 0,则程序运行时也将发生异常,运行如图:

技术分享

从结果我们可以看出一旦出现异常,程序将会立刻结束,不仅计算机和输出商的语句不被执行,而且输出“感谢使用本程序!” 的语句也不执行。那么我们该如何解决异常呢?如果我们用 if ——else语句来对各种异常情况进行来处理。我们会发现代码加入了大量的异常情况判断和处理代码,把很大一部分时间放在了处理异常代码上,放在了“堵漏洞”上,减少了编写业务代码的时间,必然影响开发效率。

  那么同样一段代码,把可能出现异常的代码放入 try 语句块中,并使用 catch 语句块捕获异常。

public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1=input.nextInt();
        try {
            System.out.println("请输入被除数:");
            int num2= input.nextInt();
            System.out.println(String.format("%d /%d =%d", num1,num2,num1/num2));
            System.out.println("感谢使用本程序!");
        } catch (Exception e) {
            System.out.println("出现错误:被除数和除数必须是整数,"+"除数不能为0");
            e.printStackTrace();
        }
    }

 

 再次输入以上的三种情况,

第一种:

技术分享

第二种:

技术分享

第三种:

技术分享

如果希望无论是否发生异常,都执行输出“感谢使用蹦本程序!” 的语句,,那么只需要在 try——catch 语句块后加 finally 块,把该语句放入finally 块,无论发生异常,finally 开中的代码总能被执行。

public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1=input.nextInt();
        try {
            System.out.println("请输入被除数:");
            int num2= input.nextInt();
            System.out.println(String.format("%d /%d =%d", num1,num2,num1/num2));
            
        } catch (Exception e) {
            System.out.println("出现错误:被除数和除数必须是整数,"+"除数不能为0");
            e.printStackTrace();
        }
        finally{
            System.out.println("感谢使用本程序!");
        }
    }

 

 结果:

技术分享

 

 即使在 try 块和 catch 块中存在 return 语句,finally 块中语句也会被执行。

public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1=input.nextInt();
        try {
            System.out.println("请输入被除数:");
            int num2= input.nextInt();
            System.out.println(String.format("%d /%d =%d", num1,num2,num1/num2));
            return;     //finally语句块仍旧会被执行
        } catch (Exception e) {
            System.out.println("出现错误:被除数和除数必须是整数,"+"除数不能为0");
            return; //finally语句块仍旧会被执行
        }
        finally{
            System.out.println("感谢使用本程序!");
        }
    }

 

执行顺序:执行 try 块或 catch 中之前的语句,执行 finally 块中的语句,执行 try 块或 catch 中的 return 语句退出。

运行结果: 

技术分享

finally 块中语句不被执行的唯一情况:在异常处理代码中执行System.exit(1),将退出Java虚拟机。

public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1=input.nextInt();
        try {
            System.out.println("请输入被除数:");
            int num2= input.nextInt();
            System.out.println(String.format("%d /%d =%d", num1,num2,num1/num2));
        } catch (Exception e) {
            System.out.println("出现错误:被除数和除数必须是整数,"+"除数不能为0");
            System.exit(1);
        }
        finally{
            System.out.println("感谢使用本程序!");
        }
    }

运行结果:

 技术分享

 

》多重catch块

  一段代码可能会引发多种类型异常,这时,可以在一个 try 语句块后面跟多个 catch 语句块,分别处理不同的异常。但排列顺序必须是从子类到父类,最后一个一般都是Execption 类,因为所有异常子类都继承自 Exception类,所以如果将父类异常放到前面,那么所有的异常都将被捕获,后面 catch 块中的子类异常讲的不到被执行的机会。当运行时,系统冲上到下分别对每个 catch 语句块处理的异常的异常类型进行检测,并执行第一个与异常类型匹配的 catch语句。执行其中的一条 catch 语句之后,其后的 catch 语句都将被忽略。

public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1=input.nextInt();
        try {
            System.out.println("请输入被除数:");
            int num2= input.nextInt();
            System.out.println(String.format("%d /%d =%d", num1,num2,num1/num2));
            
        } catch (InputMismatchException e) {
            System.err.println("被除数和除数必须是整数。");
        }catch (ArithmeticException e) {
            System.err.println("除数不能为零。");
        } catch (Exception e) {
            System.err.println("其它未知。");
        }finally{
            System.out.println("感谢使用本程序!");
        }
    }

运行结果:

技术分享

 

 》声明异常——throws

   如果一个方法体中抛出异常,我们就希望调用者能及时地捕获异常,那么如何通知调用着呢?Java 语言中通过关键字 throws 声明某个方法可能抛出的各种异常,throws 可以抛出多个异常,之间用逗号隔开。

public static void main(String[] args) {

        try {
            divide();

        } catch (Exception e) {
            System.err.println("出现错误:被除数和除数必须是整数" + "除数不能为零");

        } finally {
            System.out.println("感谢使用本程序!");
        }
    }

    public static void divide() throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1 = input.nextInt();
        System.out.println("请输入被除数:");
        int num2 = input.nextInt();
        System.out.println(String.format("%d /%d =%d", num1, num2, num1 / num2));
    }

 

   从上面看出 divide() 方法使用 throws 声明抛出了异常,并在 main 方法里面调用了此方法,通过 try —— catch 捕获了异常。如果不通过 try ——catch 处理异常,我们可以继续使用 throws 抛出异常

public static void main(String[] args) throws Exception {

            divide();

    }

    public static void divide() throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1 = input.nextInt();
        System.out.println("请输入被除数:");
        int num2 = input.nextInt();
        System.out.println(String.format("%d /%d =%d", num1, num2, num1 / num2));
    }

   但是使用这种方法需要注意:调用者抛出的异常一定要比被调用抛出的异常更大或等于。

 

》抛出异常——throw

  除了系统自动抛出异常,在编程过程中,我们往往遇到这样的情形:有些问题是系统无法自动发现并解决的,如年龄不在正长范围内、性别输入不是 “男” 或 “女” 等,此时需要程序员而不是系统来自动抛出异常,把问题提交给调用者去解决。

》使用 throw 在方法内抛出异常
public class Person {

    private String sex;

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) throws Exception {
        if ("".equals(sex) || "".equals(sex)) {
            this.sex = sex;
        } else {
            throw new Exception("性别必须是\"男\"或者\"女\"!");
        }
    }

}

 

 

public static void main(String[] args) throws Exception {

        Person person = new Person();
        person.setSex("hao");
    }

 

输出结果:

技术分享

 

 throw 和 throws 的区别表现在以下三个方面。

  》作用不同 : throw 用于在程序中抛出异常;throws 用于声明在该方法内抛出了异常。

  》使用位置不同:throw 位于方法体内部,可以作为单独语句使用;throws 必须跟在方法参数列表的后面,不能单独使用。

  》内容不同:throw 抛出一个异常对象,而且只能是一个;throws 后面跟异常类,而且可以跟多个以异常类。

 

》异常的分类

技术分享

 

 

 

  Throwable 类 :所有异常类型都是 Throwable 类的子类,它派生两个子类,即Error 和 Exception 。

  Error类 :表示紧靠程序本身无法恢复的严重错误,如内存溢出动态链接失败、虚拟机错误。应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出)。假如出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。所以在进行程序设计时,应该更关注Exception类。

  Exception 类:由Java 应用程序抛出和处理的严重错误,如需文件找不到、网络连接不通或中断。算术运算出错(如被零除)、数组下标越界、装载了一个不存在的类、对 null 对象的操作、类型转换异常类等。他的各种不同的子类分别对应不同类型的异常。

  运行时异常:包括RuntimeException 及其所有子类,不要求程序必须对它们做出处理。

  Checked 异常(非运行时异常):除了运行时异常外的其他由Exception 继承来的异常类。程序必须捕获或者声明抛出这种异常,否则会出现编译错误,无法通过编译。处理方式包括来钟:通过 try——catch 在当前位置捕获并处理异常;通过throws 声明抛出异常,交给上一级调用方法处理。

 

》自定义异常

  当 JDK 中的异常类型不能满足出现的需要时,可以自定义异常类。

public class GenderException extends Exception {

    public GenderException() {
        super();
    }

    public GenderException(String message, Throwable cause) {
        super(message, cause);
    }

    public GenderException(String message) {
        super(message);
    }

    public GenderException(Throwable cause) {
        super(cause);
    }

}

 

 

public class Person {

    private String sex;

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) throws Exception {
        if ("".equals(sex) || "".equals(sex)) {
            this.sex = sex;
        } else {
            throw new GenderException("性别必须是\"男\"或者\"女\"!");
        }
    }

}

 

Java——异常