有关异常的文章

1.文章开始前 让我们来回忆一下刚开始是我们遇到的 异常

1.算术异常 除数为 0

public class Main {
    //
    public static void main(String[] args) {
        System.out.println(10/0);
    }
}

在这里插入图片描述

2.数组下标越界

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        System.out.println(arr[100]);
    }
}

在这里插入图片描述

3.访问 null 对象 (空指针异常)

public class Main {
    public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr[10]);
    }
}

在这里插入图片描述

4.克隆时异常

class Person implements Cloneable {
    public int id;


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Main {
    public static void main(String[] args)  {
        Person person = new Person();
        Person person1 = (Person)person.clone();
    }
}



下面为 抛出异常 


class Person implements Cloneable {
    public int id;

    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person)person.clone();
    }
}

在这里插入图片描述

在这里插入图片描述

输入的数据不匹配异常

在这里插入图片描述

所谓异常指的就是程序在 运行时 出现错误时通知调用者的一种机制.
关键字 "运行时"有些错误是这样的, 例如将 System.out.println 拼写错了, 写成了 system.out.println**.**

此时编译过程中就会出错, 这是 “编译期” 出错.
而运行时指的是程序已经编译通过得到 class 文件了, 再由 JVM 执行过程中出现的错误.
异常的种类有很多, 不同种类的异常具有不同的含义, 也有不同的处理方式

防御式编程

错误在代码中是客观存在的. 因此我们要让程序出现问题的时候及时通知程序猿. 我们有两种主要的方式
LBYL: Look Before You Leap.

在操作之前就做充分的检查.(来个例子,你想牵一个女孩的手,你先问人家能不能牵手就是LBYL)

EAFP: It’s Easier to Ask Forgiveness than Permission.

“事后获取原谅比事前获取许可更容易”. 也就是先操作, 遇到问题再处理.

(这里就是强行去牵人家 手,但人家生气了 , 你 得赶紧去道歉,这就是 EAFP)

LBYL 风格的代码(不使用异常)

boolean ret = false;
ret = 登陆游戏();

if (!ret) { //如果登入失败 进行下面的操作
    
		处理登陆游戏错误;
  return;
}

ret = 开始匹配();
if (!ret) {//如果匹配失败 进行下面的操作
    
			处理匹配错误;
  return;
}
ret = 选择英雄(); // 如果选择英雄错误,进行下面操作
if(!ret) {
    处理选择英雄错误;
    return;
}
ret = 游戏确认();
if (!ret) {// 如果登入未确认 进行下面的操作
    
	处理游戏确认错误;
  return;
}

EAFP 风格的代码(使用异常)

try {
  登陆游戏();
  开始匹配();
  游戏确认();
  选择英雄();
  载入游戏画面();
 ...     
    通过 chatch 来捕抓各种异常
} catch (登陆游戏异常) {
  处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}
......

总结

对比两种不同风格的代码, 我们可以发现, 使用第一种方式, 正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱. 而第二种方式正常流程和错误流程是分离开的, 更容易理解代码

接下来让我们来使用一下 try 和 catch

异常的基本用法

捕获异常
基本语法

try{
有可能出现异常的语句 ;
}[catch (异常类型 异常对象) {
} ... ]
[finally {
异常的出口
}]


try 代码块中放的是可能出现异常的代码.

catch 代码块中放的是出现异常后的处理行为.

finally 代码块中的代码用于处理善后工作, 会在最后执行.

其中 catch 和 finally 都可以根据情况选择加或者不加

例子

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

初步了解 了异常 接下来 我们来了解一下 异常的系统机构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

像平常 的 空指针 算术 数组越级 就为 运行时异常(非受查异常)

另外 像递归 那样 如果 没有 结束 调节 就会 栈溢出 错误 和 堆溢出错误

接下来看看 Exception 的子类

在这里插入图片描述

其实我们 还能能通过 Java的帮助手册 来查找 这些异常 子类

在这里插入图片描述

也可以通过 一个小技巧来查找 (通过子类 来找父类 或者父类的父类)

在这里插入图片描述

知道这些 是不是 有 一个小问题 如果 我们 可以 知道 父类 为啥不能 直接 使用 父类去 找 异常呢?
在这里插入图片描述

使用父类 时 要注意 父类 不能在 子类 的上面

在这里插入图片描述

我们 了解 完异常 我们 回忆一下 之前 我们 使用 clone() 是 这样使用的 那么 现在 我们 就动手改造一下
在这里插入图片描述

我们手动去 找他的异常 而不是 让 jvm 去帮助我们

在这里插入图片描述

了解 finally

在这里插入图片描述

这里 finally

无论是否存在异常, finally 中的代码一定都会执行到. 保证最终一定会执行到 Scanner 的 close 方法

另外

如果 我们在方法中 没有合适的处理异常的方式, 就会沿着调用栈向上传递

在这里插入图片描述

如果 函数 是别人 写的 我们拿过来使用 是 我们咋 知道 他会抛出异常,那么我们就可以通过

关键字 throws

在这里插入图片描述

这里 我们 回到 finally

在这里插入图片描述

异常处理流程
1.程序先执行 try 中的代码

2.如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.

3.如果找到匹配的异常类型, 就会执行 catch 中的代码

4.如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.

5.无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).

6.如果上层调用者也没有处理的了异常, 就继续向上传递.

7.一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.

抛出异常

接下来 我们 来学习一下 抛出异常

在这里插入图片描述
在这里插入图片描述

注意 这里的 抛出异常 只是自定义了异常的错误 信息并不是 真正意义上的自定义异常类型

自定义异常

这里我们创建 一个 登入 框架

public class Test {
    private static  final  String name = "wanquan";
    private static  final  String password = "123";
    public static void lonin(String name,String password) {
        if(!(Test.name.equals(name))) {
            System.out.println("用户名错误");
        }
        if(!(Test.password.equals(password))) {
            System.out.println("密码错误");
        }
    }

    public static void main(String[] args) {
        这里 如果 名字 或 密码 错误 就会报错 
        lonin("wanquan","123");
        lonin("aaa","123");

    }
}

下面我们 开始 自定义异常

在这里插入图片描述

在这里插入图片描述

最后我们来实现 我们自己的异常

class nameException extends RuntimeException  {
    public nameException(String mssage) {
        super(mssage);
    }
}
class  passwordException extends RuntimeException {
    public passwordException(String massage) {
        super(massage);
    }
}
public class Test {
    private static  final  String name = "wanquan";
    private static  final  String password = "123";
    //这里使用 throws  声明 异常
    public static void lonin (String name,String password)throws  nameException ,passwordException {
        if(!(Test.name.equals(name))) {
            //System.out.println("用户名错误");
            throw new nameException("用户名错误");
        }
        if(!(Test.password.equals(password)))   {
//            System.out.println("密码错误");
            throw new passwordException("密码错误");
        }
    }

    public static void main(String[] args) {
      try{
        lonin("aaa","123");
      }catch (nameException e) {
          e.printStackTrace();
          System.out.println("用户名错误");
      }catch (passwordException e) {
          e.printStackTrace();
          System.out.println("密码错误");
      }finally {
          System.out.println("finally执行了");
      }
    }
}

最后注意事项

自定义异常通常会继承自 Exception 或者 RuntimeException
继承自 Exception 的异常默认是受查异常
继承自 RuntimeException 的异常默认是非受查异常.

这是最后了 我保证

练习

  1. 编写一个类,在其main()方法中的try块里抛出一个Exception类的对象。传递一个

    字符串参数给Exception的构造器。在catch子句里捕获此对象,并打印字符串参数,添加一个

    finally子句打印一条信息以证明这里确实得到执行

public class Main {
    public static void main(String[] args) {

        try{
            throw new Exception("我抛出异常了");

        }catch(Exception e) {
            e.printStackTrace();
        }finally {
            System.out.println("我确实被执行了");
        }
    }
}

2.定义一个对象应用并初始化为null ,尝试用此引用调用方法。把这个调用放在

try–catch子句里以捕获异常

public class Main {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        try{
            arr = null;
            System.out.println(arr[2]);
        }catch(NullPointerException e) {
            e.printStackTrace();
            System.out.println("捕获到一个空指针异常");
        }finally {
            System.out.println("fianlly执行了");
        }
    }
}

在这里插入图片描述

3.完成一个 自定义异常

class Number extends Exception {
    public Number(String message) {
        super(message);
    }
}
这里我们就 创建了一个 受查异常
public class Test4 {
    public static void func(int x) {
        try{
            if( x == 0) {
                throw  new Number("不能传0为参数");
            }
        }catch (Number e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        func(0);
    }
}
  1. 使用 while 循环 建立 类似《恢复模型》 的异常 处理 行为,它将 不断重复,知道异常不在抛出
思路 定义 一个  i = 0 只要  i<10 一直 抛出异常 知道 i == 10 结束

    public class Main {
    public static void main(String[] args) {
        int i = 0;
        while(i < 10) {
            try{
                if(i<=10){
                    throw new Exception();

                }
            }catch (Exception e) {
                e.printStackTrace();
                System.out.println("尝试网络连接"+(i+1)+"次");
                i++;
            }finally {

            }
        }
        if(i == 10) {
            System.out.println("网络连接成功");
        }
    }
}
```java

知道 i == 10 结束

    public class Main {
    public static void main(String[] args) {
        int i = 0;
        while(i < 10) {
            try{
                if(i<=10){
                    throw new Exception();

                }
            }catch (Exception e) {
                e.printStackTrace();
                System.out.println("尝试网络连接"+(i+1)+"次");
                i++;
            }finally {

            }
        }
        if(i == 10) {
            System.out.println("网络连接成功");
        }
    }
}

在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值