Javase-异常

1. 异常概述

什么是异常

①什么是异常?有什么用?
1.Java中的异常是指程序运行时出现了错误或异常情况,导致程序无法继续正常执行的现象。例如,数组下标越界,空指针异常,类型转换异常等都属于异常情况,
2、 Java提供了异常处理机制,即在程序中对可能出现的异常情况进行捕捉和处理。异常机制可以帮助程序员更好地管理程序的错误和异常情况,避免程序崩溃或出现不可预测的行为。
3.没有异常机制的话,程序中就可能会出现一些难以调试和预测的异常行为,可能导致程序崩溃,甚至可能造成数据损失或损害用户利益。因此,异常机制是一项非常重要的功能,是编写可靠程序的基础。

异常的存在形式

一句话总结, Java当中异常以类和对象的方式存在, 让我们看下面这一段代码

public class Main
	public static void main(String[] args){
			String s = null;
			System.out.print(s.toString());
		}
	}
}

上述代码明显发生了一个著名的异常 – 空指针异常
在这里插入图片描述
那这个异常的底层到底是如何发生的呢, 其实质上是new 了一个空指针异常的对象然后抛出

public class Main
	public static void main(String[] args){
			//由于这个运行时异常没有被捕获, 所以直接导致了JVM的终止运行
			throw new NullPointerException();
		}
	}
}

2. 异常的继承结构

异常的继承结构详解

①所有的异常和错误都是可抛出的,都继承了Throwable类。
②Error是无法处理的,出现后只有一个结果:JVM终止。
③Exception是可以处理的。
④Exception的分类

  1. 所有的RuntimeException的子类:运行时异常/未检查异常(UncheckedException)/非受控异常
  2. Exception的子类(除RuntimeException之外):编译时异常/检查异常(CheckedException)/受控异常

⑤编译时异常和运行时异常区别:

  1. 编译时异常特点;在编详阶段必须提前处理,如果不处理编详器报错。
    运行时异常特点;在编译阶段可以选择处理,也可以不处理,没有硬性要求。
  2. 编译时异常一般是由外部环境或外在条件引起的,如网络故障,磁盘空间不足。文件找不到等
    运行时异常一般是由程序员的错误引起的,并且不需要强制进行异常处理

为什么有编译时异常的这个说法

注意:编译时异常并不是在编译阶段发生的异常,所有的异常发生都是在运行阶段的,因为每个异常发生都是会new异常对象的,new异常对象只能在运行阶段完成。那为什么叫做编译时异常呢?这是因为这种异常必须在编译阶段提前预处理,如果不处理编译器报错,因此而得名编译时异常。

图解异常的继承结构
下面我们用starUML工具画一下异常继承体系的简图
(其实异常的机构体系十分庞大, 我们的这个图只是举了几个类作为示例)
在这里插入图片描述

3. 自定义异常

自定义异常的方法就两步

  1. 编写一个异常类继承Exception或者是RuntimeException(原则就是判断是程序员的错还是其他)
  2. 给两个构造方法, 一个无参的, 一个带有一个String参数, 调用父类的构造方法
    这个方法的灵感其实来源于源码, 上面我们的UML类继承图也指出, 其实异常继承机构中真正起作用的是Throwalbe方法

下面我们给出例子

/**
 * 年龄非法异常类
 */
public class IllegalAgeException extends Exception{
    
    //无参数的构造方法
    public IllegalAgeException(){
        super();
    }
    
    //带有一个参数String的构造方法
    public IllegalAgeException(String message){
        super(message);
    }
}
/**
 * 名字非法异常类
 */
public class IllegalNameException extends Exception{
    //无参数的构造方法
    public IllegalNameException() {
        super();
    }

    //带有一个参数String的构造方法
    public IllegalNameException(String message) {
        super(message);
    }
}

完成下面的业务逻辑

自定义异常
①定义两个编译时异常:
IlegalNameException:无效名字异常
IllegallAgeException:无效年龄异常
②完成这样的需求:
1.编写一个用户注册的方法,该方法接收两个参数,一个是用户名,一个是年龄。如果用户名长度在6-12]位,并且年龄大于18岁时,输出用户注册成功。
2.如果用户名长度不是[6-12)位时,让程序出现异常,让llegalNameException异常发生!如果年龄小于18岁时,让程序出现异常,让llegalAgeException异常发生!

下面是我们的实现的代码, 我们先通过throws把异常都抛出给上级

import powernode.exception.IllegalAgeException;
import powernode.exception.IllegalNameException;

import java.util.Scanner;

/**
 * 测试的主程序
 *  本次测试中我们的异常机制强行抛给了Main函数来处理
 *  而Main函数又上抛给虚拟机JVM进行处理, 而JVM的处理机制就是直接断掉测试程序
 */
class ExceptionTest{
    public static void main(String[] args) throws IllegalNameException, IllegalAgeException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入名字 : ");
        String name = sc.next();
        System.out.println("请输入年龄 : ");
        int age = sc.nextInt();
        UserService userService = new UserService();
        userService.register(name,age);
    }
}

/**
 * 下面是用户层, 用于接收用户的处理请求
 */
public class UserService {
    public void register(String name, int age)  throws IllegalAgeException, IllegalNameException {
        System.out.println("当前用户正在注册...");
        Sql sql = new Sql();
        sql.save(name,age);
        System.out.println("注册任务已完成...");
    }
}

/**
 * 下面是数据库层, 用来连接数据库, 在数据库中保存相关的用户信息
 */
class Sql {
    public void save(String name, int age) throws IllegalAgeException, IllegalNameException {
        //在这里对传入的参数进行处理操作
        if (name.length() < 6 || name.length() > 12) {
            throw new IllegalNameException();
        }

        if (age < 18) {
            throw new IllegalAgeException();
        }

        System.out.println("您的个人信息在数据库中保存成功...");
    }
}

4. 异常的处理

  1. 声明异常: 这是一种推卸责任的处理方式, 在方法定义的时候通过throws关键字声明异常, 告诉使用者我们的这个位置可能会出现异常, 这种处理异常的态度是, 如果发生了异常我们就上抛给调用者去解决
  2. 捕获异常: 真正意义上的去处理异常, 通过try-catch的方法进行抓住, 如果其他方法调用这个方法的时候, 如果在方法内部已经抓住了, 那么对于调用者来说是不知道异常发生的
  3. 对于运行时异常来说, 我们没有必要进行强制的处理, JVM会自动的将异常向上抛出(throws处理), 所以我们之前发生空指针异常的时候, JVM得到了异常信息之后就会直接的关掉程序
  4. 对于编译时异常来说, 就需要我们手动的处理, 我们可以选择throws把问题抛给上级, 也可以选择try-catch自己捕获住
  5. 对于异常的处理态度应该是声明跟捕获联合使用
  6. 如何进行选择: 如果异常的发生是需要调用者知道的那我们就进行throws抛出, 否则采用捕获

throws方法的具体语法
在这里插入图片描述
try-catch的基本语法
在这里插入图片描述

上面的逻辑的代码采用处理的方式可以改为下面这样

import java.util.Scanner;

/**
 * 测试的主程序
 *  本次测试中我们的异常机制强行抛给了Main函数来处理, 而Main函数又上抛给虚拟机JVM进行处理, 而JVM的处理机制就是直接断掉测试程序
 */
class ExceptionTest{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入名字 : ");
        String name = sc.next();
        System.out.println("请输入年龄 : ");
        int age = sc.nextInt();
        UserService userService = new UserService();
        try{
            userService.register(name,age);
        }catch(IllegalAgeException e) {
            e.printStackTrace();
        }catch(IllegalNameException e){
            e.printStackTrace();
        }
    }
}

5. 异常的使用

我们比较常用的其实就下面的两种方法

  1. getMessage()
    获取到最初创建异常的时候的传递出去的message(也就是那个字符串)
    其实我们分析源码就可以了解到, 当时我们调用super(message)的时候, 我们的message其实给到了throwable中的一个属性字符串, 现在我们调用getMessage()的时候实质上是返回了该字符串
  2. printStackTrace();
    打印的是异常在堆栈中的信息(也就是我们的红色字体), 该方法返回的时候是符合栈的数据结构的, 所以我们查看异常的时候应该从顶部查看(栈顶)

6. finally语句块

  1. finally语句块的代码是一定会执行的
  2. finally语句块不可以进行单独的使用, 一定要配合try块一起使用
    通常的使用结构是 try - finally / try - catch - finally
  3. finally语句块通常完成资源的释放(因为一定会执行)

思考下面的案例的执行结果

public static int m1(){
	try{
		System.out.println("try语句块");
		return 1;
	}finally{
		System.out.println("finally语句块");
	}
}

答案是
 try语句块
 finally语句块
public static int m1(){
	try{
		System.out.println("try语句块");
		System.exit(0);
	}finally{
		System.out.println("finally语句块");
	}
}

答案是
 try语句块

也就是说只有System.exit(0)方法(终止JVM的运行)才能停掉finally语句块的运行

7. 方法覆盖与异常

就一句话, 抛出的异常不可以变多可以变少
如果子类抛出了一个父类抛出异常的父类, 那么这种情况也会编译报错

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值