Loading

Java异常处理机制

异常概述

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

异常类的继承体系

exception

Java 把所有非正常的情况分为两种:异常(Exception)和错误(Error),它们都继承 Throwable 类。

异常机制

​ 在Java 中表示异常的接口是 Exception, 与其同一层次的还有一个Error接口,用于描述不可挽回的系统级错误,它们两个都继承自 Throwable 接口,这个接口是所有异常和错误的超接口。 在Java 中只有 Throwable 类型的实例才能被 (throw)或者捕获(catch),他是异常处理机制的基本组成类型。

Error

​ Error 是 程序无法处理的错误,表示运行应用程序中发生比较严重的问题。大多数错误与代码编写者的操作无关,而表示代码运行时和 JVM 出现的问题。例如:Java虚拟机运行错误,当 JVM 不再有继续执行操作所需的内存资源时, 将出现 OutOfMemoryError。这些异常发生时,Java虚拟机一般会选择线程终止 。

Exception

​ Java将异常分为两种,Checked异常和Runtime异常, Java认为Checked异常都是可以在编译阶段被处理的异常,所以它强制程序处理所有的Checked异常;而Runtime异常则无须处理。Checked异常可以提醒程序员需要处理所有可能发生的异常。

Runtime Exception

​ 运行时异常 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

Checked Exception

​ 非运行时异常(编译异常) 是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常。 当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

抛出异常

抛出异常有三种形式,一是Throws,一个Throw,还有一种系统自动抛异常。下面它们之间的异同。

Throws

​ 使用 Throws 声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理;如果main方法也不知道如何处理这种类型的异常,也可以使用 Throws 声明抛出异常,将异常交由 JVM 处理。JVM对异常的处理方法是,打印异常的堆栈信息,并终止程序运行。

​ Throws声明抛出只能在方法中使用,可以抛出多个异常类,多个异常类逗号隔开。

    void exception() throws NullPointerException,
            NumberFormatException, ArrayIndexOutOfBoundsException {
	
    }

Throw

​ 当程序出现错误时,系统会自动抛出异常;除此之外,Java 也允许程序自行抛出异常,自行抛出异常由 Throw 来完成。throw关键字作用是抛出一个异常,抛出的时候是抛出的是一个异常类的实例化对象,

Throws 和 Throw 使用

Throws 使用

/**
 * @author leizige
 */
public class Math {

    public static int div(int a, int b) throws Exception {  //有异常,交给调用方处理
        /* 计算,此处可能出现异常 */
        return a / b;
    }

}

class Test {
    public static void main(String[] args) {
        try {
            int result = Math.div(10, 2);
        } catch (Exception e) {
            /* 打印异常 */
            e.printStackTrace();
        }
    }
}

因为div使用了throws关键字声明,所以调用此方法的时候,方法必须进行异常处理。通过try...catch;

主方法抛出异常,交给JVM处理。

/**
 * @author leizige
 */
public class Math {

    public static int div(int a, int b) throws Exception {  //有异常,交给调用方处理
        /* 计算,此处可能出现异常 */
        return a / b;
    }

}

class Test {
    public static void main(String[] args) throws Exception {
        int result = Math.div(10, 0);
    }
}

运行结果:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at cn.wengzi.exception.Math.div(Math.java:10)
	at cn.wengzi.exception.Test.main(Math.java:17)

Throw 使用

public class MyException {
    public static void main(String[] args) {
        try {
            /* 手动抛出异常实例化对象 */
            throw new Exception("66666666");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Throws 和 Throw 的应用

例如,现在要使用一个相除的方法,但是在操作之前必须打印“运算开始”的信息,结束之后必须打印“异常结束”。

/**
 * @author leizige
 */
@Slf4j
public class Math {

    public static int div(int a, int b) throws Exception {  //有异常,交给调用方处理
        int result = 0;
        /* 计算,此处可能出现异常 */
        log.info("------------计算开始------------");
        result = a / b;
        log.info("------------计算结束------------");
        return result;
    }

}

class Test {
    public static void main(String[] args) {
        try {
            int result = Math.div(10, 0);
            System.err.println("计算结果:" + result);
        } catch (Exception e) {
            System.err.println("错误信息 : " + e);
        }
    }
}

执行结果:

16:12:46.188 [main] INFO cn.wengzi.exception.Math - ------------计算开始------------
错误信息 : java.lang.ArithmeticException: / by zero

以上没有计算结束,因为没有异常发生了,直接中断程序操作。所以做以下操作。

/**
 * @author leizige
 */
@Slf4j
public class Math {

    public static int div(int a, int b) {
        log.info("------------计算开始------------");
        int result = 0;
        try {
            /* 计算,此处可能出现异常 */
            result = a / b;
        } catch (Exception e) {
            /* 不抛出异常 */
        }
        log.info("------------计算结束------------");
        return result;
    }

}

class Test {
    public static void main(String[] args) {
        try {
            int result = Math.div(10, 0);
            System.err.println("计算结果:" + result);
        } catch (Exception e) {
            System.err.println("错误信息 : " + e);
        }
    }
}

执行结果:

16:15:08.252 [main] INFO cn.wengzi.exception.Math - ------------计算开始------------
16:15:08.255 [main] INFO cn.wengzi.exception.Math - ------------计算结束------------
计算结果:0

以上代码虽然执行成功了,但是异常并没有抛出去! 因为在方法中已经被自动处理了。所以要抛出异常对象,给方法调用处处理,使用throw关键字。

/**
 * @author leizige
 */
@Slf4j
public class Math {

    public static int div(int a, int b) {
        log.info("------------计算开始------------");
        int result = 0;
        try {
            /* 计算,此处可能出现异常 */
            result = a / b;
        } catch (Exception e) {
            throw e;		//抛出异常对象
        }
        log.info("------------计算结束------------");
        return result;
    }

}

class Test {
    public static void main(String[] args) {
        try {
            int result = Math.div(10, 0);
            System.err.println("计算结果:" + result);
        } catch (Exception e) {
            System.err.println("错误信息 : " + e);
        }
    }
}

执行结果:

16:18:45.405 [main] INFO cn.wengzi.exception.Math - ------------计算开始------------
错误信息 : java.lang.ArithmeticException: / by zero

If you’re going to reuse code, you need to understand that code!
posted @ 2020-12-03 16:36  不颓废青年  阅读(94)  评论(0编辑  收藏  举报