Java笔记(十一)——异常 try catch / throw / throws

1 学习中常见的异常

1、除 0 的算术异常
数学中的问题,分母不能为零。

int a = 10;
int b = 0;
System.out.println(a / b);

在这里插入图片描述
2、数组下标越界异常
超过数组下标范围。

int[] a = {1,2,3};
System.out.println(a[100]);

在这里插入图片描述
3、空指针异常
针对空引用进行了解引用就会出现这样的异常。

int [] a = null;
System.out.println(a[0]);

在这里插入图片描述
注意:
java.lang 是我们经常接触的一个包,它最大的特点就是使用起来很方便,里面的东西可以直接使用,像我们经常使用的 String 就在这个包中,现在我们所说的异常,也有很多都在这个包中。

2 区分抛出异常和编译出错

编译期:编译出错。就是我们在像 IDEA 这样的平台上进行编写时,出现的标红、红波浪线等提示。编译通过,就一定没有编译错误。
运行时:抛出异常。异常是运行过程 中出现的一种错误,异常是比较复杂的,被很多因素影响,相同的代码在不同的计算机上也可能会出现错误。

  异常其实是帮助性的,因为只有知道问题出在哪里才能有解决的办法,如果连问题出现在何处都不清楚,是很难改正的,异常就给了我们提示,明确告诉我们出现异常的原因。

3 防御式编程

1、LBYL(Look Before You Leap):操作之前进行检查,如果上一步出现了错误,就不再继续执行。
2、EAFP(It‘s Easier to Ask Forgiveness than Permission):先斩后奏。先操作,然后如果出现问题再解决。

4 try catch 处理异常

4.1 关键字

1、try :语句块中放可能会抛出异常的代码;
2、catch :语句块中放处理异常的代码,和 try 搭配使用;
3、throw : 主动的抛出一个异常(异常本质上是一个一个的对象);
4、throws :某个方法可能会抛出某些异常;
5、finally : 一般用于异常处理完毕之后的收尾。

4.2 try catch 处理示例

示例 1 :
代码中出现异常,但没有使用 try catch 捕捉处理异常,就会由 JVM 自己来处理,程序就会异常终止。异常出现位置之后的代码,就不会再运行了

int [] a = null;
System.out.println(a[0]);
System.out.println("hello");

hello 不会运行出来
在这里插入图片描述
示例 2 :
使用 try 包裹可能出现异常的代码,然后搭配使用 catch 处理异常。

try {
    System.out.println("try 中异常之前的代码");
    int [] a = null;
    System.out.println(a[0]);
    System.out.println("try 中异常之后的代码");
} catch (NullPointerException e) {
// e 类似于一个形参,当 try 的代码抛出异常之后
// e 就对应着这个异常
// 通过 e 就可以获取到异常的一些具体信息。
    System.out.println("catch 中的代码");
    System.out.println("e 中的信息:");
// 这个方法能够打印出当前出现异常的代码,对应的调用栈的信息
// 如图中的红色的信息,就是这个方法打印出来的
// 能看到,是哪个代码、哪一行出现了异常
    e.printStackTrace();
    
}
System.out.println("hello");

在这里插入图片描述
( e.printStackTrace() 和 System.out.println 打印一个在System.out中,一个在System.error中,它们会进入缓存中然后执行,缓存出来不一定谁先谁后,所以 hello 和 红色字的顺序不一定 )

try catch 执行顺序:
1、顺序执行 try 中的代码;
2、如果在 try 中出现异常,就会进入到 catch 中执行 catch 中的代码,try 中剩下的代码就不会执行了;
3、try catch 执行完毕后,执行它们之后外面的代码;
4、程序正常结束

示例 3:
catch 中异常的类型,要和抛出的异常的类型匹配,才能进行处理,否则执行不到 catch 中的逻辑。使用 try catch 时,需要很明确 try 中都会抛出哪些异常。

try {
    System.out.println("try 中异常之前的代码");
    int [] a = {1,2,3};
    System.out.println(a[100]);
    System.out.println("try 中异常之后的代码");
} catch (NullPointerException e) {
    System.out.println("catch 中的代码");
}
System.out.println("hello");

在这里插入图片描述
示例 4 :
一对多。如果 try 中可能有多个异常的话,使用多个 catch 进行捕捉处理,多个 catch 之间就像时分支语句一样,异常匹配到哪个就执行哪个 catch 中的逻辑。

try {
    System.out.println("try 中异常之前的代码");
    int [] a = {1,2,3};
    System.out.println(a[100]);
    System.out.println("try 中异常之后的代码");
} catch (NullPointerException e) {
    System.out.println("catch 空指针异常");
}catch (ArrayIndexOutOfBoundsException e){
    System.out.println("catch 数组下标越界");
}
System.out.println("hello");

在这里插入图片描述
示例 5 :
可以使用一个 catch 语句,捕获多个异常(如果我们程序对以上两种异常的处理逻辑是一样的话)。使用 “ | ”,相当于逻辑或,抛出的着若干个异常中的任何一个,都会触发 catch。

try {
    System.out.println("try 中异常之前的代码");
    int [] a = {1,2,3};
    System.out.println(a[100]);
    System.out.println("try 中异常之后的代码");
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
    System.out.println("catch 空指针异常");
}
System.out.println("hello");

在这里插入图片描述
Exception e 是一个级别很高的父类,空指针异常、数组下标越界异常,都是 Exception 的子类。在进行 catch 匹配的时候不要求类型一模一样,如果抛出的异常是 catch 参数的异常的子类,也可以执行到 catch 中的逻辑。这个本质上就是一个 “ 向上转型 ”。

Exception e = new NullPointerException();

4.3 加入 finally 处理

示例 6 :
try catch 在使用的时候会涉及到代码的跳转,使用 finally 放在 try catch 的后面,finally 中的逻辑是一定会执行的,所以在其中放善后的工作 。
(1) 出现异常

try {
    System.out.println("try 中异常之前的代码");
    int [] a = {1,2,3};
    System.out.println(a[100]);
    System.out.println("try 中异常之后的代码");
} catch (Exception e) {
    System.out.println("catch 空指针异常");
}finally{
    System.out.println("finally 中的代码");
}
System.out.println("hello");

在这里插入图片描述
(2) 没出现异常

try {
    System.out.println("try 中异常之前的代码");
    int [] a = {1,2,3};
    System.out.println(a[0]);
    System.out.println("try 中异常之后的代码");
} catch (Exception e) {
    System.out.println("catch 空指针异常");
}finally{
    System.out.println("finally 中的代码");
}
System.out.println("hello");

在这里插入图片描述
可以看到,无论出现异常还是没有出现异常,finally 中的逻辑都一定会执行到。

示例 7 :
示例 6 中的使用finally 回收资源确实是一个有保证的方式,但是代码比较繁杂,因此,Java1.7 提供的 try with resourse 机制来完成这个操作会更简洁。
用 try catch 的代码:

Scanner scanner = null;
try {
    scanner = new Scanner(System.in);
}catch (NullPointerException e){
    System.out.println("空指针异常");
}finally {
    scanner.close();
}

用 try with resourse 简化,就不用写 finally 和其中的scanner.close(),会自动关闭 scanner :

try (Scanner scanner = new Scanner(System.in)){
}catch(NullPointerException e){
    System.out.println("空指针异常");
}

示例 8 :
如果当前方法中没有合适的 catch ,异常就会沿着调用栈,向上传递。
原本的代码如下;

    func1();

public static void func1(){
    func2();
}
private static void func2() {
    try{
        int[] a = {1,2,3};
        System.out.println(a[100]);
    }catch (ArrayIndexOutOfBoundsException e){
        System.out.println("数组下标越界异常");
    }
}

若是在 fun2 中没有找到 try catch 来捕获处理异常,就会往上传递,然后在 func1 中找 try catch;

    func1();

public static void func1(){
    try {
        func2();
    } catch (ArrayIndexOutOfBoundsException e){
        System.out.println("数组下标越界异常");
    }
}
private static void func2() {
        int[] a = {1,2,3};
        System.out.println(a[100]);
}

如果 func1 再没有,就再向上传递;

    try {
        func1();
    } catch (ArrayIndexOutOfBoundsException e){
        System.out.println("数组下标越界异常");
    }

public static void func1(){
    try {
        func2();
    } catch (ArrayIndexOutOfBoundsException e){
        System.out.println("数组下标越界异常");
    }
}
private static void func2() {
        int[] a = {1,2,3};
        System.out.println(a[100]);
}

如上三段代码,都是一样的结果,都能捕捉并处理异常。
在这里插入图片描述
如果代码一直往上传递,到最后也没有找到 try catch ,就还是由 JVM 来进行处理,像示例 1 中那样打印异常调用栈,然后异常终止,后面的代码不会执行。

4.4 throw 主动抛出异常

被抛出的异常,实际就是一个对象。在这里我们还是根据一个简单的算术异常来看,在除法方法中,如果分母为 0 ,就会出现异常,我们主动抛出一个异常 ArithmeticException,让 try catch 捕捉到并打印出错误调用栈。

    try{
        int ret = divide(10,0);
    }catch(ArithmeticException e){
        e.printStackTrace();
    } 
    System.out.println("hello");

public static int divide(int x,int y) throws ArithmeticException{
    if (y == 0){
    // 抛出的异常其实就是一个对象,ArithmeticException 是一个类
    // 在 ArithmeticException 后面加上字符串做说明,是可以打印出来的
        throw new ArithmeticException("此处抛出一个算术异常");
    }
        return x / y;
}

在这里插入图片描述

4.5 thows与throw不一样

标注当前的方法,可能会抛出啥样的异常。例如,这里我们标注出 divide 可能会抛出 ArithmeticException。thrpws 是将异常交给上级处理。

    public static int divide(int x,int y) throws ArithmeticException{
        if (y == 0){
            throw new ArithmeticException("此处抛出一个算术异常");
        }
        return x / y;
    }

4.6 注意return时的顺序

    System.out.println(func1());

private static int func1() {
    try{
        return 10;
    }finally{
        return 20;
    }
}

最后的结果为 20。因为 try 在 return 之前会先去执行 finally,在执行 finally 的时候碰到了 return 20,就返回20然后结束了。

5 Java异常体系

在这里插入图片描述

首先,Throwable 是一个接口,Error 和 Exception 实现 Throwable 接口(箭头表示继承或实现);

其次,Error 是系统级别的异常,JVM 内部使用的,除了很底层一般程序媛不应该使用这个体系;Exception 是应用级别的异常,我们会经常使用这个;

最后,异常总共的可以划分为:受查异常和非受查异常。
受查异常:(黄色)如果某个方法中抛出了这个异常,那么就必须对这个异常进行显示的处理,所谓显示的处理就是 trycatch 捕获并处理异常 和 使用 throws 声明可能会抛出的异常。
非受查异常:(紫色)可以不显示的处理。主要有两种,Error:出现 Error 时,说明情况非常严重,一般 JVM 出现了问题,此时应用级别的程序媛是无能为力的;RuntimeException:一些常见的异常,影响没有很大。 除了这两个,其他的就是 受查异常。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值