Bootstrap

java中的异常

什么是异常

java中的异常是指java程序在运行时可能出现的错误或非正常情况。例如在程序中试图打开一个根本不存在的文件,在程序中除0。
异常是否出现,通常取决于程序的输入、程序中对象的当前状态以及程序所处的运行环境。
程序抛出异常后,会对异常进行处理。异常处理将会改变程序的控制流程,出于安全性考虑,同时避免异常程序影响其他正常程序的运行,操作系统通常将出现异常的程序强行终止,并弹出系统错误提示。

> public class test1 {
    public static void main(String[] args) {
        int result = divide(4, 0);
        System.out.println(result);
    }
   public static int divide(int x,int y){
            int result=x/y;
            return result;
    }
}

在这里插入图片描述
由上可知,程序抛出了算术异常(ArithmeticException),提示运算时出现了被0除的情况。异常发生后,程序会立即结束,无法继续向下执行。
ArithmeticException是一个异常类,java提供了大量的异常类,每一个异常类都表示一种预定义的异常,这些异常类都继承自java.lang包下的Throwable类,
在这里插入图片描述

Throwable类是所有异常类的父类,它有两个直接子类:Error类和Exception类,其中,Error类代表程序中产生的错误,Exception类代表程序中产生的异常。

● Error类称为错误类,它表示java程序运行时产生的系统内部错误或资源耗尽的错误,这类错误比较严重,仅靠修改程序本身是不能恢复执行的。例如,使用java命令运行一个不存在的类就会出现Error错误。
● Exception类称为异常类,它表示程序本身可以处理的错误,在java程序中进行的异常处理,都是针对Exception类及其子类的。在Exception类的众多子类中有一个特殊的子类——RuntimeException类,该类及其子类用于表示运行时异常。Exception类的其他子类都用于表示编译时异常。

从JavaAPI中查阅可知,Error错误类的子类:
在这里插入图片描述
Examption错误类的子类:
在这里插入图片描述

Throwable常用方法

方法声明功能描述
String getMessage()返回异常的消息字符串
String toString()返回异常的简单信息描述
void printStack Trace()获取异常类名和异常信息以及异常出现在程序中的位置,把信息输出到控制台

运行时异常和编译时异常

在实际开发中,经常会在程序编译时产生异常,这些异常必须处理,否则程序无法正常运行,这种异常被称为编译时异常,也称为check异常。
还有一种异常是在程序运行时产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因为被称为运行时异常,也称为unchecked异常。

编译时异常

在Exception类中,除了RuntimeException类以外,其他子类都是编译时异常。java编译器会对编译时异常进行检查。出现异常必须对其进行处理。
处理编译时异常的两种方式:
● 使用try…catch语句对异常进行捕获处理。
● 使用throws关键字声明抛出异常,由调用者对异常进行处理。

运行时异常

RuntimeException类及其子类都是运行时异常。运行时异常是在程序进行时由java虚拟机自动进行捕获的,java编译器不会对异常进行检查。不需要上述语句或关键字声明,程序也能编译通过,只是在运行过程可能报错。

常见的运行时异常:

运行时异常描述
ArithmeticException算术异常
IndexOutOfBoundException索引越界异常
ClassCastException类型转换异常
NullPointerException空指针异常
NumberFormatException数字格式化异常

运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复,例如,通过数组的索引访问数组的元素时,如果索引超过了数组范围,就会发生索引越界异常,代码如下:
int[]arr=new int[5];
System.out.println(arr[6])

运行时产生数组越界异常

异常处理及其语法

异常的产生及处理

一般情况下,当程序在运行过程中发生了异常时,系统会捕获抛出的异常对象并输出相应的信息,同时终止程序的运行。这种情况并不是用户所期望的,因为需要让程序接收和处理异常对象,从而避免影响其他代码的执行。

当一个异常类的对象被捕获或接收后,程序就会发生流程跳转,系统中止当前的流程而跳转到专门的异常处理语句块,或直接跳出当前程序和java虚拟机回到操作系统。

处理异常的5个关键字

关键字功能描述
try放置可能引发异常的代码块
catch后面对应异常类型和代码块,该代码用于处理这种类型的异常
finally主要用于回收在try代码块里打开的物理资源 ,如,数据库连接,网络连接和磁盘文。异常机制保证finally代码块总是被执行
threw用于抛出一个实际的异常,它可以单独作为语句来抛出一个具体的异常对象
throws用在方法签名中,用于声明该方法可能抛出的异常

try…catch语句

在进行除0运算时发生了异常导致程序立即终止,所以程序无法继续执行发生异常后的代码。为了使异常发生后的程序代码正常运行,程序需要捕获异常并进行处理。
java提供了try…catch语句用于捕获并处理异常,其语法格式如下:

try{
代码块
}catch(ExceptionType e){
代码块
}

try代码中编写可能发生异常的java语句,在catch代码种编写针对异常进行处理的代码。
当try代码块中的程序发生了异常时,系统会将异常的信息封装成一个异常对象,并将这个对象传递给catch代码进行处理。
catch代码块需要一个参数指明它能够接收的异常类型,这个参数必须是Exception类或其子类。
编写try…catch语句时,需要注意以下几点:

● try代码块是必须的
● catch代码块可以有多个,但捕获父类异常的catch代码块必须位于捕获子类异常的catch代码块后面
●catch代码块必须位于try代码块后面

try…catch语句的异常处理流程图如下:

Created with Raphaël 2.3.0 开始 执行try代码中的语句 执行try代码 中的语句 是否发生异常 catch 代码中的 参数类型是否匹配 发生的异常 执行catch代码块中的语句 结束 程序中断执行 yes no yes no

对除0运算中的异常信息进行捕获:

public class test1 {
    public static void main(String[] args) {
        try {
            int result = divide(4, 0);
            System.out.println(result);
        }catch (Exception e)
        {
            System.out.println("捕获的异常信息为:"+e.getMessage());
        }
        System.out.println("程序继续向下执行");
    }
   public static int divide(int x,int y){
            int result=x/y;
            return result;
    }
}

在这里插入图片描述
在try代码块中,发生异常的语句后面的代码是不会被执行的。

finally语句

有时候希望一些语句无论程序是否发生异常都需要执行,这时就可以在try…catch语句后加一个finally代码块。
finally代码块是try…catch…finally或try…finally结构的一部分,finally代码块只能出现在try…catch或try代码块之后,不能单独出现。
语法结构如下:

try{
代码块
}catch(Exceptiontype e){
代码块
}finally{
代码块
}

try…catch…finally语句的异常处理流程图如下:

Created with Raphaël 2.3.0 开始 执行try代码中的语句 执行try代码 中的语句 是否发生异常 catch 代码中的 参数类型是否匹配 发生的异常 执行catch代码块中的语句 执行finally代码中的语句 结束 yes no yes no
public class test1 {
    public static void main(String[] args) {
        try {
            int result = divide(4, 0);
            System.out.println(result);
        }catch (Exception e)
        {
            System.out.println("捕获的异常信息为:"+e.getMessage());
            return;//用于结束当前的方法
        }finally{
            System.out.println("进入finnally代码块");
        }
        System.out.println("程序继续向下执行");
    }
   public static int divide(int x,int y){
            int result=x/y;
            return result;
    }
}

在这里插入图片描述

在catch语句中添加了return语句作为方法的结束,第13行代码就不会执行了。但是finall代码块中的代码会执行,不受return语句影响。无论程序发生异常还是使用return语句结束,final代码块中的语句都会执行。
在程序设计时,通常会使用finally代码块处理必须做的事情,如释放系统资源。

System(0)表示退出当前的java虚拟机,任何代码都不能再执行。

抛出异常

有些异常不需要处理,此时可以将异常抛出,让该类的调用者处理,java提供了throws关键字和throw关键字用于抛出异常。

throws关键字

实际开发中,大部分情况下程序开发者会调用别人的方法,并不知道别人编写的方法是否会发生异常。
java允许在方法的后面使用throws关键字声明该方法有可能发生的异常,这样调用者在调用该方法时,就明确地知道该方法有异常,必须对异常进行处理。
语法格式:

修饰符 返回值类型 方法名(参数1,参数2,…)throws 异常类1,异常类2,…{
方法体
}

public class test1 {
    public static void main(String[] args) {
        int result=divide(4,2);
        System.out.println(result);
    }
   public static int divide(int x,int y) throws Exception{
            int result=x/y;
            return result;
    }
}

在这里插入图片描述
传入第二个参数为2,运行程序依然会提示错误,这是因为定义divide()方法时使用throws关键字声明了该方法可能抛出的异常,调用者必须在调用divide()方法时对抛出的异常进行处理。

public class test1 {
    public static void main(String[] args) {
        try {
            int result=divide(4,2);
            System.out.println(result);
        }catch(Exception e)
        {
            e.printStackTrace();//打印捕获的异常信息
        }

    }
   public static int divide(int x,int y) throws Exception{
            int result=x/y;
            return result;
    }
}

在调用方法时,如果不知道如何处理声明抛出的异常,也可以使用throws关键字继续将异常抛出,这样程序也能编译通过。使用throws关键字重抛异常时,程序发生了异常,并且上一层调用者也无法处理异常时,那么异常会继续被向上抛出,最终直到系统接收到异常,中止程序执行。

public class test1 {
    public static void main(String[] args)throws Exception{//将divide方法声明的异常继续抛出
        try {
            int result=divide(4,0);
            System.out.println(result);
        }catch(Exception e)
        {
            e.printStackTrace();
        }

    }
   public static int divide(int x,int y) throws Exception{
            int result=x/y;
            return result;
    }
}

在这里插入图片描述
main方法继续使用throws关键字将Exception抛出,程序虽然可以通过编译,但并没有对异常进行处理,程序中止运行。

throw关键字

与throws关键字不同,throw关键字用于方法体内,抛出的是一个异常实例,每次只能抛出一个异常实例。
语法格式

throw ExceptionInstance
在方法中,通过throw关键字抛出异常后,还需要使用throws关键字try…catch语句对异常进行处理。
如果throw抛出的是ErrorRuntimeException或它们的子类异常对象,则无需使用上述对异常进行处理。

使用throw关键字抛出异常,通常有以下两种情况

●当throw关键字抛出的异常时编译时异常时,有两种处理方式:
Ⅰ在try代码块里使用throw关键字抛出异常,通过try代码块捕获该异常;
Ⅱ在一个有throws声明的方法中使用throw关键字抛出异常,把异常交给该方法的调用者处理。
●抛出的异常时运行时异常时,程序既可以显示使用try…catch语句捕获并处理该异常,也可以完全不理会该异常,而把该异常交给方法的调用者处理。

public class test1 {
    public static void printAge(int age) throws Exception{
        if(age<0){
            throw new Exception("输入的年龄有误,必须是正整数");
        }
        else {
            System.out.println("此人年龄为:"+age);
        }
    }
    public static void main(String[] args) {
        int age=-1;
        try {
            printAge(age);
        }catch (Exception e){
            System.out.println("捕获的异常信息为:"+e.getMessage());
        }
    }
}

在这里插入图片描述
上述代码中,throws声明的printAge方法中使用throw抛出异常实例,将异常交给main方中的调用者处理,交给catch方法处理该异常。

自定义异常类

自定义异常类解决程序开发中程序中特有的异常情况。
自定义异常类必须继承Exception类或其子类。
使用自定义异常类,需要用到throw关键字。使用throw关键字在方法中声明异常的实例对象。声明格式如下

throw Exception 异常对象

class DivideByMinusException extends Exception{
    public DivideByMinusException(){//调用Exception无参构造方法
        super();
    }
    public DivideByMinusException(String message)//调用Exception有参构造方法
    {
        super(message);
    }
}
public class test1 {
    public static void main(String[] args) {
        int result=divide(4,-2);
        System.out.println(result);
    }
    public static int divide(int x,int y){
        if(y<0){
            throw new DivideByMinusException("除数是负数");
        }
        int result=x/y;
        return result;
    }
}

在这里插入图片描述
程序编译时出现了异常,在一个方法内使用throw关键字抛出异常对象时,需要使用try…catch语句对抛出的异常进行处理,或在divide方法后面使用throws关键字声明抛出对象,由该方法的调用者处理。

class DivideByMinusException extends Exception{
    public DivideByMinusException(){//调用Exception无参构造方法
        super();
    }
    public DivideByMinusException(String message)//调用Exception有参构造方法
    {
        super(message);
    }
}
public class test1 {
    public static void main(String[] args) {
        try {
            int result=divide(4,-2);
            System.out.println(result);
        }catch (DivideByMinusException e){
            System.out.println(e.getMessage());
        }

    }
    public static int divide(int x,int y) throws DivideByMinusException{
        if(y<0){
            throw new DivideByMinusException("除数是负数");
        }
        int result=x/y;
        return result;
    }
}

在这里插入图片描述

;