【Java编程进阶】Java异常详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1. 异常

异常就是不正常的意思是程序执行过程中出现的非正常情况最终导致 JVM 非正常终止。异常是 Java 中提供的一种识别及响应错误情况的一致性机制。有效地异常处理能使程序更加健壮、易于调试。

在这里插入图片描述
在Java语言中将程序执行中发生的不正常情况称为异常 开发过程中的语法错误和逻辑错误不是异常此时无法通过编译程序无法运行异常是指程序运行过程中的问题。

示例

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int c = a / b;

        System.out.println(a + "/" + b + "=" + c);
    }
}

当程序运行到int c = a / b时JVM 会 new 一个异常对象

new ArithmeticException("/ by zero");

并且 JVM 将异常对象抛出打印输出信息到控制台。

在这里插入图片描述

Java 中异常发生的原因有很多例如

  • 用户输入了非法数据
  • 要打开的文件不存在
  • 网络通信时连接中断
  • JVM内存溢出
  • 这些异常有的是因为用户错误引起有的是程序错误引起的还有其它一些是因为物理错误引起的。

2. 异常的体系

Java 异常其实是为了帮助我们找到程序中的问题其本质其实是一个类产生异常就是创建异常对象并抛出这个异常对象。

异常的根类是 Java.lang.Trowable是所有异常和错误是超类其有两个子类分别是 Error 类和 Exception 类。平时我们常说的异常主要是这里的 Exception 类这里也主要是对该类就行讲解。

在这里插入图片描述

Exception 类是指编译期异常类即编译Java代码即写代码期出现的问题其子类 RutimeException 类称为运行期异常指 Java 运行中出现的问题只要我们处理掉异常程序就可以继续执行。Error 类是程序无法处理的错误表示运行应用程序中较严重问题。

Java异常分为可查异常和不可查异常。正确的程序在运行过程中很容易出现情理可容的异常状况。可查异常虽然是异常状况但在一定程度上它的发生是可以预计的而且一旦发生这种异常状况就必须采取某种方式进行处理。

除了 RuntimeException 及其子类以外其他的Exception类及其子类都属于可查异常最典型的是IO类异常。

RuntimeException 与其子类和错误 Error 属于不可查异常编译器不要求强制处置的异常。

3. Error

Error 是指系统内部的错误这类错误由系统进行处理程序本身无需捕获处理。比如内存溢出错误OOM堆栈溢出错误StackOverflowError等一般发生这种情况JVM会选择终止程序。此时必须修改代码程序才能执行。

示例

//堆栈溢出错误
public class Test {
    public static void recursionMethod() {
        recursionMethod();// 无限递归下去
    }
    public static void main(String[] args) {
        recursionMethod();
    }
}

报错信息

Exception in thread "main" java.lang.StackOverflowError
	at Test.recursionMethod(Test.java:4)
	at Test.recursionMethod(Test.java:4)
	at Test.recursionMethod(Test.java:4)
	at Test.recursionMethod(Test.java:4)
    ...

4. 异常产生的过程

通过了解异常产生的过程我们可以深入学习如何处理异常通过下面的例子来学习异常产生的过程定义一个数组定义一个获取数组指定索引位置元素的值此时程序就有可能产生数组索引越界的异常

public class Test {
    public static void main(String[] args) {
        int[] arr={1,2,3};
        int b=getElement(arr,3);
        System.out.println(b);
    }
    public static int getElement(int[] arr,int index){
        int a=arr[index];
        return a;
    }
}

异常信息

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
	at Test.getElement(Test.java:8)
	at Test.main(Test.java:4)

程序在执行 getElement() 方法时传入了 arr 和3两个参数目的是访问数组 arr 索引为3的元素的值但是由于数组 arr 的长度为3此时 JVM就会检测到程序出现了异常JVM执行一下操作

第一步 JVM根据异常的原因创建了一个异常的对象包含了异常产生的内容原因和位置。

new ArrayIndexOutOfBoundsException("3");

第二步因为 getElement() 方法中没有异常处理的逻辑(try…catch)所以 JVM 把异常对象抛给了该方法的调用者 main 方法来处理这个异常。

当 main 方法接收到这个异常对象后由于它也没有异常处理的逻辑所以继续把异常对象抛给了 main 方法的调用者 JVM 来处理。当 JVM 接收到这个异常对象后首先把异常对象的内容输出打印在控制台其次采用中断处理结束这个 Java 程序。

5. throw 关键字

我们可以使用 throw 在指定的方法中抛出异常使用时必须写在方法的内部且 throw 后创建的对象必须是 Exception 类的对象或者是其子类的对象。

throw 抛出异常后我们必须处理这个异常如果 throw 后创建的是 RuntimeException 类或者其子类的对象我们可以不处理默认交给 JVM 处理即打印异常中断程序。如果创建的是编译时写代码时异常对象此时必须使用 throws 或者 try…catch 来处理异常。

示例在定义一个方法时我们要先对方法传递的参数进行合法性校验如果传递的参数不合法我们就要使用抛出异常的方法告知方法的调用者参数不合法。

public class Test {
    public static void main(String[] args) {
        int[] arr=null;
        int b=getElement(arr,3);
        System.out.println(b);
    }
    public static int getElement(int[] arr,int index){
        if(arr==null) {
            throw new NullPointerException("传递的数组为空");
        }
        if(index<0||index>=arr.length){
            throw new ArrayIndexOutOfBoundsException("传递的参数超出数组下标") ;
        }
        int a=arr[index];
        return a;
    }
}

此时由于传入的数组为空值且new NullPointerException("传递的数组为空")为运行时异常类的对象所以异常信息会被打印在控制台并且中断程序。

6. 异常处理

6.1 throws 关键字

使用 throws 关键字处理异常是今天要谈论的异常处理的第一种方式。前面说到在方法中使用 throw 抛出异常对象后必须处理这个异常对象此时我们就可以使用 throws 把这个异常对象抛给方法的调用者最终抛给 JVM 做中断处理。

使用 throws 关键字有以下几个注意事项

  • throws 必须写在方法声明后面
  • throws 关键字后面使用的必须是 Exception 类或者其子类
  • 方法体中抛出多个异常对象就要在 throws 后面声明多个异常如果方法体中抛出的异常有字父类的关系则只需要声明父类异常

当我们调用了声明异常的方法后就必须对这个异常进行处理要么继续使用 throws 抛出异常对象交给方法的调用者处理最终由 JVM 做中断处理。要么使用 try…catch 自己处理异常。

示例定义一个方法对方法输入的文件路径的参数做合法性判断。

import java.io.FileNotFoundException;

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
        //定义一个方法对传递的路径参数做合法性校验
        readFile("c://b.txt");
    }

    public static void readFile(String fileName) throws FileNotFoundException {
        if (!(fileName.equals("c://a.txt"))) {
            throw new FileNotFoundException("传递的文件路径不是c://a.txt");
        }
    }
}

此时如果 readFile() 方法传入的参数不是 "c://a.txt" 程序运行到调用该方法的位置时JVM 对程序做中断处理打印异常内容到控制台。

在这里插入图片描述

6.2 try…catch 捕获异常

现在要谈论的是异常处理的第二种方法使用 try…catch 捕获异常。前面我们使用 throws 声明异常显然是有局限性的程序运行到调用声明异常的方法时如果程序出现异常则后序代码不会执行。而此方法可以对程序中出现的问题做指定方式的处理。

语法

try{
    //可能出现异常的代码
}catch(){//括号中定义异常变量用来接收try中抛出的异常对象try中抛出多个异常对象可以使用多个catch处理异常对象
    //异常处理逻辑
   }

如果 try 中出现了异常就会抛出异常对象并执行 catch 中的语句执行完继续执行 try…catch 后的语句。否则不会执行 catch 中的语句执行完 try 中的语句直接执行 try…catch 后的语句。

示例定义一个方法对方法输入的文件路径的参数做合法性判断如果出现异常则捕获异常。

import java.io.FileNotFoundException;

public class Test {
    public static void main(String[] args) {
        try {
            //定义一个方法对传递的路径参数做合法性校验
            readFile("c://b.txt");
        } catch (FileNotFoundException e) {
            System.out.println("传递的文件路径不是c://a.txt");
        }
        System.out.println("后续代码");
    }

    public static void readFile(String fileName) throws FileNotFoundException {
        if (!(fileName.equals("c://a.txt"))) {
            throw new FileNotFoundException("传递的文件路径不是c://a.txt");
        }
    }
}

此时如果 readFile() 方法中传入的参数不是 c://txt 则捕获异常给 catch 中的语句块做异常处理执行完以后继续执行 try…catch 后面的语句。

在这里插入图片描述

7. 获取异常信息

Throwable 中定义了三个方法用于获取异常信息分别是

  • public String getMessage() 返回 Trowable 的简短描述
  • public String toString() 返回 trowable 的详细描述
  • public String printStackTrace JVM 打印异常信息默认调用此方法其描述最详细包括异常产生的内容原因和位置

示例1使用 getMessage() 方法获取异常信息

import java.io.FileNotFoundException;

public class Test {
    public static void main(String[] args) {
        try {
            //定义一个方法对传递的路径参数做合法性校验
            readFile("c://b.txt");
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        }
    }

    public static void readFile(String fileName) throws FileNotFoundException {
        if (!(fileName.equals("c://a.txt"))) {
            throw new FileNotFoundException("传递的文件路径不是c://a.txt");
        }
    }
}

此时如果程序出现异常异常信息显示为

在这里插入图片描述

示例2使用 toString() 方法获取异常信息

 try {
            //定义一个方法对传递的路径参数做合法性校验
            readFile("c://b.txt");
        } catch (FileNotFoundException e) {
            System.out.println(e.toString());
        }

异常信息为

在这里插入图片描述

示例3使用 printStackTrace() 方法获取异常信息

 try {
            //定义一个方法对传递的路径参数做合法性校验
            readFile("c://b.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

此时的异常信息为

在这里插入图片描述

8. finally 代码块

在使用 try…catch 捕获异常时如果 try 中代码出现了异常则创建异常对象抛给 catch 语句块中的异常处理逻辑代码处理此时 try 中后续的代码将不会执行。有时我们需要这个位置的代码继续执行例如需要释放资源则出现了 fianlly 代码块。

无论程序是否出现异常finally 代码块中的代码都会执行。且 finally 不可以单独使用必须使用在 try 代码后后序 IO 流中继续学习。

示例

import java.io.FileNotFoundException;

public class Test {
    public static void main(String[] args) {
        try {
            //定义一个方法对传递的路径参数做合法性校验
            readFile("c://b.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            System.out.println("资源释放");
        }
    }

    public static void readFile(String fileName) throws FileNotFoundException {
        if (!(fileName.equals("c://a.txt"))) {
            throw new FileNotFoundException("传递的文件路径不是c://a.txt");
        }
    }
}

此时程序出现了异常但是 finally 中的语句继续执行。

java.io.FileNotFoundException: 传递的文件路径不是c://a.txt
	at Test.readFile(Test.java:17)
	at Test.main(Test.java:7)
资源释放

9. 自定义异常

系统定义的异常主要用来处理系统可以预见的常见运行错误对于某个应用所特有的运行错误需要编程人员根据特殊逻辑来创建自己的异常类。

例如在我们输入成绩的时候往往会有一个范围而这个范围不是JVM能够识别的此时就需要自己定义异常类。

语法格式

public class 自定义异常类名 extends Exception{}

使用继承 Exception 类的类定义自定义异常逻辑类而 Exception 中常用的构造方法也可以被子类用super调用。同样还可以使用继承自 runtimeException 类的类实现运行时的自定义异常类。

示例

//栈操作异常自定义异常
public class StackOperationException extends Exception{ // 编译时异常
    public MyStackOperationException(){

    }

    public MyStackOperationException(String s){
        super(s);
    }
}

10 Java编程基础教程系列

【Java编程进阶】封装继承多态详解

【Java编程进阶】抽象类和接口详解

【Java编程进阶】Object类及常用方法详解

在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java