异常的捕获和处理

目录

一、异常

1.异常概述

1.1认识异常

1.2Java异常体系结构

2.Java异常处理机制

2.1异常处理

2.2捕获异常

2.2.1使用try-catch捕获异常

2.2.2使用try-catch-finally处理异常

2.2.3使用多重catch处理异常

2.3抛出异常

2.3.1使用throws声明抛出异常

2.3.2使用throw抛出异常

2.4自定义异常

2.5异常链


一、异常

1.异常概述

1.1认识异常

异常是指程序在运行过程中出现的非正常情况。

public class Main {

    public static void main(String[] args) {
        int i=1,j=0,res;
        System.out.println("begin");
        res=i/j;//算术运算异常
        System.out.println("end");
    }

}

一旦程序发生异常将会立即结束,因此“end”没有输出。

1.2Java异常体系结构

异常在Java中被封装成了各种异常类。

异常的捕获和处理_第1张图片

程序中常见的异常: 

Exception 设计时异常 异常层次结构的根类
IOException 设计时异常 IO异常的根类,属于非运行时异常
FileNotFoundException 设计时异常 文件操作时,找不到文件
RuntimeException 运行时异常 运行时异常的根类,RuntimeException及其子类,不要求必须处理
ArithmeticException 运行时异常 算术运算异常
lllegalArgumentException 运行时异常 方法接收到非法参数
ArrayIndexOutOfBoundsException 运行时异常 数组越界访问异常
NullPointerException 运行时异常 尝试访问null对象的成员时发生的空指针异常
ArrayStoreException 运行时异常 数据存储异常,写数组操作时,对象或数据类型不兼容
ClassCastException 运行时异常 类型转换异常
IIIegalThreadStateException 运行时异常 试图非法改变线程状态,例如试图启动一个已经运行的线程
NumberFormatException 运行时异常 数据格式异常,试图把一字符串非法转换成数值

2.Java异常处理机制

2.1异常处理

Java中的异常处理机制依靠5个关键字:try、catch、finally、throw、throws。这些关键字提供了两种异常处理方式:

(1)用try、catch、finally来捕获和处理异常

try块中包含可能会抛出异常的代码

catch块中用户捕获和处理指定类型的异常

finally块中的代码无论是否发生异常都会被执行,通常用于释放资源或清理操作

(2)使用throw、throws来抛出异常

throw关键字用于手动抛出异常对象。

throws关键字用于在方法声明中指定可能抛出的异常类型,表示该方法可能会抛出该类型的异常,由调用者来处理。

2.2捕获异常
2.2.1使用try-catch捕获异常
public class Main {

    public static void main(String[] args) {
        try {
            int i=1,j=0,res;
            System.out.println("begin");
            res=i/j;
            System.out.println("end");
        }catch (Exception e){
            System.out.println("caught");
            e.printStackTrace();
        }
        System.out.println("over");
    }

}
  • 如果try语句块中的所有语句正常执行完毕,没有发生异常,那么catch语句块中的所有语句将被忽略。
  • 如果try语句块在执行过程中发生异常,并且这个异常与catch语句块中声明的异常类型匹配,那么try语句块中剩下的代码都将被忽略,相应的catch语句块将会被执行。匹配是指catch中所处理的异常类型与try中发生的异常类型完全一致或者是它的父类。
  • 如果try语句块在执行过程中发生异常,而抛出的异常在catch语句块中没有被声明,那么程序立即终止运行,程序被强迫退出。
  • catch语句块中可以加入用戶自定义处理信息,也可以调用异常对象的方法输出异常信息,常用的方法如下:
    void prinStackTrace() :输出异常的堆栈信息。堆栈信息包括程序运行到当前类的执行流程,它将输出从方法调用处到异常抛出处的方法调用的栈序列。
    String getMessage() :返回异常信息描述字符串,该字符串描述了异常产生的原因,是 printStackTrace() 输出信息的一部分。
2.2.2使用try-catch-finally处理异常

无论try块中是否发生异常,finally语句块中的代码总能被执行。

public class Main {

    public static void main(String[] args) {
        try {
            int i=1,j=0,res;
            System.out.println("begin");
            res=i/j;
            System.out.println("end");
        }catch (ArithmeticException e){
            System.out.println("caught");
            e.printStackTrace();
        }finally {
            System.out.println("finally");
        }
        System.out.println("over");
    }

}
  • 如果try语句块中所有语句正常执行完毕,程序不会进入catch语句块执行,但是finally语句块会被执行。 
  • 如果try语句块在执行过程中发生异常,程序会进入到catch语句块捕获异常, finally语句块也会被执行。
  • try-catch-finally结构中try语句块是必须存在的,catch、finally语句块为可选,但两者至少出现其中之一。

即使在catch语句块中存在return语句,finally语句块中的语句也会执行。发生异常时的执行顺序是,先执行catch语句块中return之前的语句,再执行finally语句块中的语句,最后执行catch语句块中的return语句退出。

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

public class Main {

    public static void main(String[] args) {
        try {
            int i=1,j=0,res;
            System.out.println("begin");
            res=i/j;
            System.out.println("end");
        }catch (ArithmeticException e){
            System.out.println("caught");
            e.printStackTrace();
            System.exit(1);
        }finally {
            System.out.println("finally");
        }
        System.out.println("over");
    }

}

异常的捕获和处理_第2张图片

public class Main {

    public static void main(String[] args) {
        System.out.println(method());
    }

    private static int method() {
        int i=1;
        try {
            i++;//2
            System.out.println("try block,i="+i);//try block,i=2
            return i;//2
        }catch (Exception e){
            i++;
            System.out.println("catch block,i="+i);
        }finally {
            i=10;
            System.out.println("finally block,i="+i);//finally block,i=10
        }
        return i;
    }
}

异常的捕获和处理_第3张图片

 

public class Main {

    public static void main(String[] args) {
        System.out.println(method());
    }

    private static int method() {
        int i=1;
        try {
            i++;
            System.out.println("try block,i="+i);//try block,i=2
            return i;
        }catch (Exception e){
            i++;
            System.out.println("catch block,i="+i);
            return i;
        }finally {
            i=10;
            System.out.println("finally block,i="+i);//finally block,i=10
            return i;//10
        }
    }
}

异常的捕获和处理_第4张图片

2.2.3使用多重catch处理异常

catch语句块的排列顺序必须是从子类到父类,最后一个一般是Exception类。这是因为在异常处理中,catch语句块会按照从上到下的顺序进行匹配,系统会检测每个catch语句块处理的异常类型,并执行第一个与异常类型匹配的catch语句块。如果将父类异常放在前面,子类异常的catch语句块将永远不会被执行,因为父类异常的catch语句块已经处理了异常。

一旦系统执行了与异常类型匹配的catch语句块,并执行其中的一条catch语句后,其后的catch语句块将被忽略,程序将继续执行紧随catch语句块的代码。 

子类异常应该放在前面,父类异常应该放在后面。 

import java.util.InputMismatchException;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        try {
            System.out.println("计算开始:");
            int i,j,res;
            System.out.println("请输入被除数:");
            i=input.nextInt();
            System.out.println("请输入除数:");
            j=input.nextInt();
            res=i/j;
            System.out.println(i+"/"+j+"="+res);
            System.out.println("计算结束");
        }catch (InputMismatchException e){
            System.out.println("除数和被除数都必须是整数!");
        }catch (ArithmeticException e){
            System.out.println("除数不能为0!");
        }catch (Exception e){
            System.out.println("其他异常"+e.getMessage());
        }finally {
            System.out.println("感谢使用本程序!");
        }
        System.out.println("程序结束!");
    }


}

第一种:被除数发生异常

异常的捕获和处理_第5张图片 

 第二种:除数发生异常

异常的捕获和处理_第6张图片

第三种:除数为0

异常的捕获和处理_第7张图片

2.3抛出异常
2.3.1使用throws声明抛出异常

如果在一个方法体内抛出了异常,并希望调用者能够及时地捕获异常,Java语言中通过关键字throws声明某个方法可能抛出的各种异常,以通知调用者。throws可以同时声明多个异常,之间用逗号隔开。

import java.util.InputMismatchException;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        try {
            divide();
        }catch (InputMismatchException e){
            System.out.println("除数和被除数都必须是整数!");
        }catch (ArithmeticException e){
            System.out.println("除数不能为0!");
        }catch (Exception e){
            System.out.println("其他异常"+e.getMessage());
        }finally {
            System.out.println("感谢使用本程序!");
        }
        System.out.println("程序结束!");
    }
    private static void divide() throws Exception{
        Scanner input=new Scanner(System.in);
        System.out.println("计算开始:");
        int i,j,res;
        System.out.println("请输入被除数:");
        i=input.nextInt();
        System.out.println("请输入除数:");
        j=input.nextInt();
        res=i/j;
        System.out.println(i+"/"+j+"="+res);
        System.out.println("计算结束");
    }

}
2.3.2使用throw抛出异常

在Java语言中,可以使用throw关键字来自行抛出异常。

package structure;

public class Main {
    public static void main(String[] args) {
        Person1 person=new Person1();
        try {
            person.setName("扈三娘");
            person.setAge(18);
            person.setGender("男女");
            person.print();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class Person1{
    private String name="";
    private int age=0;
    private String gender="男";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

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

    }
    public void print(){
        System.out.println("姓名:"+this.name+"性别:"+this.gender+"年龄:"+this.age);
    }
}

异常的捕获和处理_第8张图片

  • 如果 throw 语句抛出的异常是 Checked 异常,则该 throw 语句要么处于 try 块里,显式捕获该异常,要么放在一个带 throws 声明抛出的方法中,即把该异常交给该方法的调用者处理; 
  • 如果 throw 语句抛出的异常是 Runtime 异常,则该语句无须放在 try 块里,也无须放在带 throws 声明抛出的方法中;程序既可以显式使用 try...catch来捕获并处理该异常,也可以完全不理会该异常,把该异常交给该方法调用者处理。
  • 自行抛出Runtime 异常比自行抛出Checked 异常的灵活性更好。同样,抛出 Checked 异常则可以让编译器提醒程序员必须处理该异常。

 throw和throws的区别:

1.作用不同:throw用于程序员自行产生并抛出异常,throws用于声明该方法内抛出了异常。
2.使用位置不同:throw位于方法体内部,可以作为单独的语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
3.内容不同:throw抛出一个异常对象,只能是一个;throws后面跟异常类,可以跟多个。

2.4自定义异常

当JDK中的异常类型不能满足程序的需要时,可以自定义异常类。步骤:

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

②编写异常类的构造方法,向父类构造方法传入异常描述信息,并继承父类的其他实现方法。

③实例化自定义异常对象,并在程序中使用throw抛出。

package structure;

public class Main {
    public static void main(String[] args) {
        Person1 person=new Person1();
        try {
            person.setName("扈三娘");
            person.setAge(18);
            person.setGender("男女");
            person.print();
        }catch (GenderException e){
            e.printStackTrace();
        }
    }
}
//自定义异常类
class GenderException extends Exception{
    public GenderException(String message){
        super(message);
    }
}
class Person1{
    private String name="";
    private int age=0;
    private String gender="男";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

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

    }
    public void print(){
        System.out.println("姓名:"+this.name+"性别:"+this.gender+"年龄:"+this.age);
    }
}

自定义异常可能是编译时异常,也可能是运行时异常 。

1.如果自定义异常类继承Excpetion,则是编译时异常。
特点:方法中抛出的是编译时异常,必须在方法上使用throws声明,强制调用者处理。
2.如果自定义异常类继承RuntimeException,则运行时异常。
特点:方法中抛出的是运行时异常,不需要在方法上用throws声明。

2.5异常链

有时候我们会捕获一个异常后再抛出另一个异常。

顾名思义就是将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,这样逐层抛出。

在要抛出的对象中使用 initCause() 方法,添加上一个产生异常的信息; getCause() 可以获取当前异常对象的上一个异常对象。

你可能感兴趣的:(java,开发语言)