异常 Exception 02

六、异常处理

1、基本介绍

异常处理就是当异常发生时,对异常处理的方式。

2、异常处理的方式

  1. try-catch-finally
    程序员在代码中捕获发生的异常,自行处理
  2. throws
    将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是 JVM

3、示意图

(1) try-catch-finally 处理机制

	try {
	
		代码/可能有异常
		
	} catch(Exception e) {
	
		捕获到异常
		1、当异常发生时
		2、系统将异常封装成 Exception 对象e,传递给catch
		3、得到异常对象后,程序员自己处理
		4、注意,如果没有发生异常,catch代码块不执行
	
	} finally {
	
		1、不管try代码块是否有异常发生,都要执行finally
		2、所以,通常将释放资源的代码放在finally
	
	}

(2)throws 处理机制图

JVM 调用main方法,main调用 f1,f1 中 调用 f2,f2 抛出(发生)异常。
f2 抛出异常可以使用 ① try-catch-finally ② throws 机制,扔出去,f2 说它不管,抛给 f1(因为是 f1 调用它的),
f1也有两种选择,它也可以继续丢出去 throws。
扔给JVM,处理异常非常暴力,直接①输出异常信息 ②退出程序。
在这里插入图片描述

(1)try-catch-finally 和 throws 二选一
(2)如果程序员,没有显式处理异常,默认throws

在这里插入图片描述

try-catch

  1. Java提供 try 和 catch 块来处理异常。try 块用于包含可能出错的代码。catch 块用于处理 try 块中发生的异常。可以根据需要在程序中有多个 try…catch 块。finally 可写可不写。
  2. 基本语法
try {
	可疑代码
	将异常生成对应的异常对象,传递给catch} catch(异常){
	对异常的处理
}
没有finally也是可以滴
  1. IDEA中的快捷键

CTRL + ALT + T

  1. 【重要】注意事项
    ① 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块。【案例A】
    ② 如果异常没有发生,则顺序执行try的代码块,不会进入到catch。
    ③ 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等) 则使用如下代码 - finally {}。
    ④ 可以有多个catch语句,捕获不同的异常(进行不同的业务处理,要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException 在前),如果发生异常,只会匹配一个catch。【案例B】
    ⑤ 可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接退出/崩掉。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。

【举例A】

public static void main(String[] args) {
      try {
           String str = "XXXXXXX";
           System.out.println("=========");
           int a = Integer.parseInt(str);
           System.out.println("+++++++++");
           System.out.println("数字:" + a);
       } catch (NumberFormatException e) {
           e.printStackTrace();
       }
}

int a = Integer.parseInt(str);这句话会报错,直接跳到 catch块
在这里插入图片描述
【举例B】

public class TryCatchDetail02 {
    public static void main(String[] args) {
        try {
            Person person = new Person();
            person = null;
            System.out.println(person.getName());//NullPointerException
            int n1 = 10;
            int n2 = 0;
            int res = n1/n2;//ArithmeticException
        } catch (NullPointerException e) {
            System.out.println("空指针异常=" + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("算数异常=" + e.getMessage());
        } catch (Exception e) {
            //Exception是 NullPointerException 和ArithmeticException的父类
            System.out.println(e.getMessage());
        } finally {

        }
    }
}

class Person {
    private String name = "jack";

    public String getName() {
        return name;
    }
}

throws

1、介绍

  1. 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些·异常进行处理,而由该方法的调用者负责处理。
  2. 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异
    常类型可以是方法中产生的异常类型,也可以是它的父类。
public class Throws01 {
    public static void main(String[] args) {

    }
    public void f2() throws FileNotFoundException {
//        创建了一个文件对象
        FileInputstream fis = new FileInputStream("d ://aa.txt");
    }
}

说明:
① 这里的异常:编译异常 FileNotFoundException(后面学到 IO)
② 使用throws,【throws FileNotFoundException】 抛出异常,让调用f2()的方法处理。
③ throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。解释: FileNotFoundException的父类是Exception,也可以写 【throws Exception】
④ 在方法声明中用throws语句可以声明抛出异常的列表
【throws FileNotFoundException,NullPointerException, ArithmeticException】

2、注意事项

  1. 对于编译异常,程序中必须处理,比如 try-catch 或者throws
  2. 对于运行时异常,程序中如果没有处理,默认就是throws的方式处理
  3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型【案例A】
  4. 在throws过程中,如果有方法 try-catch,就相当于处理异常,就可以不必throws
  5. 【案例B】
  6. 【案例C】

【案例A】
子类重写的方法,所抛出的异常类型和父类抛出的异常一致

class Father {
    public void method() throws RuntimeException {
    }
}

class Son extends Father {
    @Override
    public void method() throws RuntimeException {
    }
}

这样也可以,子类重写的方法,所抛出的异常类型为父类抛出的异常的类型的子类型

class Father {
    public void method() throws Exception {
    }
}

class Son extends Father {
    @Override
    public void method() throws RuntimeException {
    }
}

【案例B】
在这里插入图片描述
f1 和 f3 都在相同的类里,且都是静态方法,按理来说可以直接调用。怎么在 f1 中调用 f3 报错??
分析:
FileNotFoundException是编译异常,f3 会抛出异常给调用它的 f1,但是在 f1 中没有处理。
因为f3()方法抛出的是一个编译异常。即这时,就要求 f1()必须处理这个编译异常。
解决方法 ① 让 f1 方法 throws ② try-catch

【案例C】

    public static void f4() {
        f5();
    }
    public static void f5() throws ArithmeticException {

    }

分析:
① 在 f4() 中调用方法 f5() 是OK
② 原因是 f5() 抛出的是运行异常
③ 而java中,并不要求程序员显示处理,因为有默认处理机制

自定义异常

1、基本概念

当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。

2、自定义异常的步骤

  1. 定义类:自定义异常类名 (程序员自己写) 继承Exception或RuntimeException
  2. 如果继承 Exception,属于编译异常
  3. 如果继承 RuntimeException,属于运行异常(一般来说,继承RuntimeException)

3、实例

当我们接收Person对象年龄时,要求范围在18-120之间,否则抛出一个自定义异常(要求继承 RuntimeException),并给出提示信息。
CustomException.java

public class CustomException {
    public static void main(String[] args) {
        int age = 80;
        if(!(age >= 18 && age <=120)) {
            throw new AgeException("年龄要在 18-120之间。");
        }
        System.out.println("你的年龄输入正确。");
    }
}
class AgeException extends RuntimeException {
    public AgeException(String message) {
        super(message);
    }
}

① 一般情况下,我们自定义异常是继承RuntimeException
② 即把自定义异常做成运行时异常,好处时,我们可以使用默认的处理机制

4、throw和throws的区别

在这里插入图片描述

【例题】

public class ThrowException {
    public static void main(String[] args) {
        try {
            ReturnExceptionDemo.methodA();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        ReturnExceptionDemo.methodB();

    }
}

class ReturnExceptionDemo {
    static void methodA() {
        try {
            System.out.println("进入方法A");
            throw new RuntimeException("制造异常");
        } finally {
            System.out.println("用A方法的finally");
        }
    }

    static void methodB() {
        try {
            System.out.println("进入方法B");
            return;
        } finally {
            System.out.println("调用B方法的finally");
        }
    }
}

在这里插入图片描述
分析!!!!!

程序从main函数开始
【执行】ReturnExceptionDemo.methodA();
------------------------ReturnExceptionDemo------------------------------------
进入ReturnExceptionDemo类寻找静态方法methodA
【执行】System.out.println("进入方法A");
【输出1】进入方法A
【执行】throw new RuntimeException("制造异常");
抛出异常: new RuntimeException("制造异常") 进入类RuntimeException的构造方法,并且传递参数
进入源代码查看,发现RuntimeExceptionException的子类,ExceptionThrowable的子类。
Throwable源码:
{
    private String detailMessage;

    public Throwable(String message) {
        fillInStackTrace();
        detailMessage = message;
    }
}
此时 属性detailMessage = "制造异常";
【执行】finally中的内容
【输出2】用A方法的finally
【返回main函数】
------------------------------main函数------------------------------------------
main捕捉到了异常,进入catch
【执行】System.out.println(e.getMessage());
Throwable类中的源码为 :
public String getMessage() {
        return detailMessage;
    }
【输出3】制造异常
【执行】ReturnExceptionDemo.methodB();
------------------------ReturnExceptionDemo------------------------------------
【输出4】进入方法B
【输出5】调用B方法的finally
  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值