侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

异常

coydone
2021-01-09 / 0 评论 / 0 点赞 / 374 阅读 / 7,194 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-01,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

异常概述

异常指在程序的运行过程中所发生的不正常事件。如所需文件找不到、网络连接不通或连接中断、数组下标越界等。异常会中断正在运行的程序。

在Java的异常处理机制中,引进了很多用来描述和处理异常的类,称为异常类。异常类定义中包含了该类异常的信息和对异常进行处理的方法。

所谓异常处理,就是指程序在出现问题时依然可以正确的执行完。

下图为被0除时程序运行发生异常:

如程序实现用户控制台输入被除数和除数,计算结果并输出商。

import java.util.Scanner;
public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入被除数:");
        double num1 = sc.nextDouble();
        System.out.print("请输入除数:");
        double num2 = sc.nextDouble();
        System.out.println(num1+"除以"+num2+"的结果为:"+num1/num2);
    }
}

当输入正确时:

当输入错误时:

从运行结果可以看出,一旦出现异常程序将会立即结束。

使用条件语句来对异常情况进行处理:

import java.util.Scanner;
public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入被除数:");
        double num1 = 0.0;
        if(sc.hasNextDouble()){//如果输入的是double类型
            num1 = sc.nextDouble();
        }else {
            System.out.println("程序退出!");
            System.exit(1);//结束程序
        }
        System.out.print("请输入除数:");
        double num2 = 0.0;
        if(sc.hasNextDouble()){//如果输入的是double类型
            num2 = sc.nextDouble();
            if (0==num2){
                System.out.println("输入的除数不能为0,程序退出!");
                System.exit(1);//结束程序
            }
        }else {
            System.out.println("程序退出!");
            System.exit(1);//结束程序
        }
        System.out.println(num1+"除以"+num2+"的结果为:"+num1/num2);
    }
}

使用条件语句进行异常处理缺点:

  • 代码臃肿,加入了大量的异常情况判断和处理代码。

  • 程序员把相当多的时间放在了异常处理的代码上,影响开发效率。

  • 很难穷举所有的异常情况,程序任旧不健壮。

  • 异常处理代码和业务代码交织在一起,影响代码的可读性,加大日后程序维护难度。

所以Java提供了异常处理机制。

异常处理机制

Java是采用面向对象的方式来处理异常的。处理过程:

  • 抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE。

  • 捕获异常:JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。

Java异常类层次

JDK中定义了很多异常类,这些类对应了各种各样可能出现的异常事件,所有异常对象都是派生于Throwable类的一个实例。如果内置的异常类不能够满足需要,还可以创建自己的异常类。

Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。Java异常类的层次结构如下图所示。

异常 说明
Exception 异常层次结构的根类
ArithmeticException 算术错误异常,如以0作为除数
ArrayIndexOutOfBoundsException 数组下标越界
NullPointerException 尝试访问null对象成员
ClassNotFoundException 不能加载所需的类
InputMismatchException 欲得到的数据类型与实际输入的类型不匹配
IllegalArgumentException 方法接受到非法参数
ClassCastException 对象强制类型转换出错
NumberFormatException 数字格式转换异常,如把“abc”转换成数字

在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性。

Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。

Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。

Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作“引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。

异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。

Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。

  • 运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、**IndexOutOfBoundsException(下标越界异常)**等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

  • 非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

Java异常处理:Java采用异常处理机制,将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁,并易于维护。

  • Java提供的是异常处理的抓抛模型。

  • Java程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常

  • 如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法中处理,它继续被抛给这个调用方法的调用者。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常

  • 如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。

  • 程序员通常只能处理Exception,而对Error无能为力。

try-catch-finally

异常处理是通过try-catch-finally语句实现的。

try{
    ......  //可能产生异常的代码
}
catch( ExceptionName1 e ){
    ......  //当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e ){
    ......  //当产生ExceptionName2型异常时的处置措施
}  
[ finally{
    ......   //无条件执行的语句
}  ]
  • try,捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。

  • catch (Exceptiontype e),在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

  • 捕获异常的有关信息:与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。

    • getMessage():用来得到有关异常事件的信息。

    • printStackTrace():用来跟踪异常事件发生时执行堆栈的内容。

  • finally捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。不论在try、catch代码块中是否发生了异常事件,finally块中的语句都会被执行。finally语句是可选的。

throws

声明抛出异常是Java中处理异常的第二种方式。

如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显式地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

在方法声明中用 throws 子句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

public void readFile(String file)  throws FileNotFoundException {
    //......
    // 读文件的操作可能产生FileNotFoundException类型的异常
    FileInputStream fis = new FileInputStream(file);
    //......
}

重写方法声明抛出异常的原则:重写方法不能抛出比被重写方法范围更大的异常类型。

public class A {
    public void methodA() throws IOException {
       //......
    }
}
public class B1 extends A {
    public void methodA() throws FileNotFoundException {
        //......
    }
}
public class B2 extends A {
    public void methodA() throws Exception {   //error
        //......
    }
}

throw

在Java语言中,可以使用throw关键字来自行抛出异常。在方法内部通过throw抛出异常。

public class Person {
    private String name = "";
    private int age = 0;
    private String sex = "男";
    public void setSex(String sex) throws Exception{
        if(sex.equals("男")||sex.equals("女")){
            this.sex = sex;
        }else {
            throw new Exception("性别必须为男或者女!");
        }
    }
    public void print(){
        System.out.println("性别是:"+this.sex);
    }
    //测试代码
    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setSex("Male");
            p.print();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

throw和throws的区别

1、作用不同:throw用于程序员自行产生并抛出异常,throws用于声明该方法内抛出了异常。

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

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

try-with-resource自动关闭Closable接口的资源

Java中,JVM的垃圾回收机制可以对内部资源实现自动回收,给开发者带来了极大的便利。但是JVM对外部资源(调用了底层操作系统的资源)的引用却无法自动回收,例如数据库连接,网络连接以及输入输出IO流等。这些连接就需要我们手动去关闭,不然会导致外部资源泄露,连接池溢出以及文件被异常占用等。

JDK7之后,新增了”try-with-reasource”。它可以自动关闭实现了AutoClosable接口的类,实现类需要实现close()方法。”try-with-resources声明”,将try-catch-finally简化为try-catch,这其实是一种语法糖,在编译时仍然会进行转化为try-catch-finally语句。

public class Test {
    public static void main(String[] args) {
        try (FileReader reader = new FileReader("d:/a.txt")) {
            char c = (char) reader.read();
            char c2 = (char) reader.read();
            System.out.println("" + c + c2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

自定义异常

用户自定义异常类MyException,用于描述数据取值范围错误信息。用户自己的异常类必须继承现有的异常类。

步骤:

1、定义异常类,并继承Exception或者RuntimeException。

2、编写异常类的构造方法,并继承父类的实现。

 class MyException extends Exception {
     private int idnumber;
     public MyException(String message, int id) {
         super(message);
         this.idnumber = id;
     } 
     public int getId() {
         return idnumber;
     }
 }

受检与非受检异常

受检异常:Exception(编译器异常)

定义方法时必须声明所有可能会抛出的exception;在调用这个方法时,必须捕获它的checked exception,不然就得把它的exception传递下去;exception是从java.lang.Exception类衍生出来的。例如:IOException,SQLException就属于Exception。

非受检异常:RuntimeException(运行时异常)

在定义方法时不需要声明会抛出runtime exception;在调用这个方法时不需要捕获这个runtime exception;runtime exception是从java.lang.RuntimeException或java.lang.Error类衍生出来的。例如:NullPointException,IndexOutOfBoundsException就属于runtime exception。

0

评论区