Java的异常体系

一、异常的定义

Java中的异常:

1、错误(Error):是指JVM系统内部错误、资源耗尽等严重情况。程序员对此错误一般无能为力。

2、例外(Exception):则是指因编程错误或偶然的外在因素导致的一般性问题,程序员是可以进行处理的。

注意!

一般我们在Java中所说的异常,其实指代的就是“例外”。

二、异常层级结构

图示结构:

1641373075086

|----Object类

​ |-------- Throwable 类(所有的Error 和 Exception的父类)

​ |--------Error类(描述错误的,程序员是无能为力的)

​ |--------Exception类(描述的是例外,程序员是可以进行处理的)【研究的重点】

​ |----------- RuntimeException(运行时异常)【只有在程序执行起来后才会暴露出来的异常】

​ 还有一部分异常属于“检查性”异常,在编码的时候就会主动的提示进行处理

三、常见异常

3.1、运行时异常

常见几种异常(运行时异常):

  • 类型转化异常 ClassCastException

  • 空指针异常 NullPointerException

  • 数字格式化异常 NumberFormatException

以上这几种异常,都是在程序运行的过程中,才会引发的异常;

3.2、检查性异常

package com.exception.demo;

public class Car {


    private Car() {

    }

    public Car(String name) {

    }

}
package com.exception.demo;

public class Car_Test {
	
	public static void main(String[] args) {
		
		try {
			//动态加载一个指定的类
			Class    carClas = Class.forName("com.it.www.exceptiontest.Car");
			//通过类结构,调用无参数的构造方法创建对象;
			Object  obj = carClas.newInstance();
			
		} catch (ClassNotFoundException e) {//包名或者是类名写错了,无法找到这个类;
			e.printStackTrace();
		} catch (InstantiationException e) {  //没有相对应的构造方法,则会抛出这个异常;
			e.printStackTrace();
		} catch (IllegalAccessException e) { //构造存在,但是访问权限不够;
			e.printStackTrace();
		}	
		
	}

}

常见几种异常(检查性异常):

  • 实例化异常 InstantiationException

  • 不规则访问 IllegalAccessException

  • 类不能找到 ClassNotFoundException

以上这几种异常,都是属于检查性异常,在编写代码的过程中开发工具会进行主动的提示,必须要处理;

四、异常的处理

4.1、try-catch方式处理异常

在Java语言中,针对运行时异常,我们推荐不进行处理,针对检查性异常必须要进行处理的,那么如何来处理这些检查性异常呢?

异常处理的语法格式:

try{
    //可能会产生异常的Java程序代码;
}catch(异常类型 e){
    //产生对应的异常需要执行的代码部分;
}catch(异常类型 e){
    //产生对应的异常需要执行的代码部分;
}.......
finally{
   //不管是否产生异常,都会被执行的部分,主要用于资源的释放;        
}

执行流程

  • 程序从 try 里面的代码开始执行
  • 出现异常,就会跳转到对应的 catch 里面去执行
  • 执行完毕之后,程序还可以继续往下执行

检查性异常和运行时异常的区别

  • 检查性异常

  • 都是Exception类及其子类

  • 必须显示处理,否则程序就会发生错误,无法通过编译

  • 运行时异常

  • 都是RuntimeException类及其子类

  • 无需显示处理,也可以和编译时异常一样处理

针对检查性异常,必须要手动进行处理:

package com.exception.demo;

public class Car_Test {

    public static void main(String[] args) {
        try {
            // 动态加载一个指定的类
            Class carClas = Class.forName("om.exception.demo.Car");
            // 通过类结构,调用无参数的构造方法创建对象;
            Object obj = carClas.newInstance();
        } catch (ClassNotFoundException e) {// 包名或者是类名写错了,无法找到这个类;
            e.printStackTrace();
        } catch (InstantiationException e) {  // 没有相对应的构造方法,则会抛出这个异常;
            e.printStackTrace();
        } catch (IllegalAccessException e) { // 构造存在,但是访问权限不够;
            e.printStackTrace();
        }
    }
}

注意!

1、finally表示不管是否会产生异常,都会被执行的部分,这主要是用于进行资源的释放,当然从语法的角度是可以省略的;

2、被监测的代码如果产生多种类型的异常,就会对应的产生多个catch的部分,在多个catch部分的顺序是有要求的,我们不能将父类前置到子类的前面;

try {
         // 动态加载一个指定的类
         Class carClas = Class.forName("om.exception.demo.Car");
         // 通过类结构,调用无参数的构造方法创建对象;
         Object obj = carClas.newInstance();
     } catch (Exception e) {// 包名或者是类名写错了,无法找到这个类;
         e.printStackTrace();
     } catch (InstantiationException e) {  // 没有相对应的构造方法,则会抛出这个异常;
         e.printStackTrace();
     } catch (IllegalAccessException e) { // 构造存在,但是访问权限不够;
         e.printStackTrace();
     }

image-20240801103554274

3、针对return与finally配合使用,首先会执行finally,然后在继续返回

4.2、Throwable成员方法

方法名说明
public String getMessage()返回此 throwable 的详细消息字符串
public String toString()返回此可抛出的简短描述
public void printStackTrace()把异常的错误信息输出在控制台
package com.exception.demo;

public class ThrowableDemo {
    public static void main(String[] args) {
        System.out.println("开始");
        method();
        System.out.println("结束");
    }

    public static void method() {
        try {
            int[] arr = {1, 2, 3};
            System.out.println(arr[3]); // new ArrayIndexOutOfBoundsException();
            System.out.println("这里能够访问到吗");
        } catch (ArrayIndexOutOfBoundsException e) { // new ArrayIndexOutOfBoundsException();
//            e.printStackTrace();

            // public String getMessage():返回此 throwable 的详细消息字符串
//            System.out.println(e.getMessage());
            // Index 3 out of bounds for length 3

            // public String toString():返回此可抛出的简短描述
//            System.out.println(e.toString());
            // java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

            // public void printStackTrace():把异常的错误信息输出在控制台
            e.printStackTrace();
//            java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//            at com.itheima_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
//            at com.itheima_02.ExceptionDemo02.main(ExceptionDemo02.java:11)

        }
    }
}

4.3、throws 和 throw的使用

4.3.1、throws 使用

定义格式

public void 方法() throws 异常类名 {
    
}

代码:

package com.exception.demo;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("开始");
//        method();
        try {
            method2();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println("结束");
    }

    // 检查性异常
    public static void method2() throws ParseException {
        String s = "2048-08-09";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date d = sdf.parse(s);
        System.out.println(d);
    }

    // 运行时异常
    public static void method() throws ArrayIndexOutOfBoundsException {
        int[] arr = {1, 2, 3};
        System.out.println(arr[3]);
    }
}

注意事项

  • 这个throws格式是跟在方法的括号后面的
  • 检查性异常必须要进行处理,两种处理方案:try…catch …或者 throws,如果采用 throws 这种方案,将来谁调用谁处理
  • 运行时异常可以不处理,出现问题后,需要我们回来修改代码

4.3.1、throw 使用

异常的抛出

可以将产生的异常进行继续向外抛出,让调用者进行捕获和处理。

package com.exception.demo;


public class ExceptionDemo02 {

	public static void main(String[] args) {

		ExceptionDemo02 demo = new ExceptionDemo02();
		// 调用者----全然不知method1方法中的所有的异常;
		demo.method1();

		// 调用者----针对使用了throws进行对外声明的操作,那么我们在调用的时候,就不能视而不见,必须要进行手动处理;
		try {
			demo.method2();
		} catch (ClassNotFoundException e) {
			// 设置自己的处理方式;
			e.printStackTrace();
		}

		try {
			demo.method3();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

	}

	// 第一种形式:在method1方法内部,我们针对异常进行了内部处理。
	public void method1() {
		try {
			Class personClas = Class.forName("com.it.www.exceptionapp.Person");
			Object obj = personClas.newInstance();
			System.out.println(obj);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 第二种形式:在method2方法内部,我们针对异常进行了内部处理,但是同时我们又将异常进行了抛出.
	// 这时,我们需要在产生异常的位置,通过throw关键字进行继续抛出的声明,并且以方法为单位使用throws对外进行声明。
	public void method2() throws ClassNotFoundException {
		try {
			Class personClas = Class.forName("com.it.www.exceptionapp.Person");
			Object obj = personClas.newInstance();
			System.out.println(obj);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw e; // 将ClassNotFoundException继续向外抛出;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	// 第三种形式:在method3方法内部我们不会进行任何的处理,全部通过throws统一对外进行声明,哪里调用,就在哪里进行处理;
	public void method3() throws ClassNotFoundException,
			InstantiationException, IllegalAccessException {
		Class personClas = Class.forName("com.it.www.exceptionapp.Person");
		Object obj = personClas.newInstance();
	}
		
}

说明:

以后在开发的过程中,如果我们编写的代码是大量作为工具的形式被大家使用,那么针对内部的异常可以直接使用throws关键字对外做声明,谁使用谁处理。

如果是自己编写的功能业务,比较独立或者是不经常进行共用,那么我们可以在自己的内部进行处理。

4.3.3、throws和throw的区别

image-20240801110045331

五、自定义异常

虽然Java内部提供了非常丰富的异常处理机制,还是满足不了我们开发的需求,比如:我们针对年龄进行限制,这时我们就需要掌握自定义异常的处理方式:我们模仿Java内部定义各种异常类的模式,推出我们自己针对某个模块或者是某个业务来编写自己的异常类;

package com.exception.demo;

import java.util.Scanner;

class ScoreException extends Exception {

    public ScoreException() {
    }

    public ScoreException(String message) {
        super(message);
    }

}

public class CustomExceptions {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入分数:");

        int score = sc.nextInt();

        Teacher t = new Teacher();
        try {
            t.checkScore(score);
        } catch (ScoreException e) {
            e.printStackTrace();
        }
    }
}

class Teacher {
    public void checkScore(int score) throws ScoreException {
        if (score < 0 || score > 100) {
//            throw new ScoreException();
            throw new ScoreException("你给的分数有误,分数应该在0-100之间");
        } else {
            System.out.println("成绩正常");
        }
    }
}

image-20240801110803991

提示!

自定义异常类就需要借助于Java内部的异常类(可以是Exception 、 也可以使用RuntimeException)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值