Java第十三课 异常(超简单)
目录
前言:
一、什么是异常?
二、异常体系
2.1 常见的异常
2.1.1(索引越界异常)
2.1.2(算术异常)
2.1.3(类型转换异常)
2.1.4(数字格式异常)
2.1.5(非法参数异常)
2.2 Throwable
2.2.1 错误VS异常
2.2.2 异常种类
三、异常传播
3.1 代码演示:
3.2 运行结果:
3.3 代码分析:
四、异常抛出
4.1 自动抛出
4.2 手动抛出
前言:
本篇文章旨在了解异常,为后面学习抛出异常打好基础。
感谢大家的观看。
首先,我问大家一个问题:
我们为什么要学习异常?
一个庞大的程序,总是避免不了错误的出现,维护就显得至关重要。
意外在生活中每时每刻都在发生。
程序,也有意外。
面对意外,我们的程序需要容错。
抛出异常--可以让我们明确错误发生的事实;
捕获异常--可以阻止我们程序崩溃;
释放资源--可以保护我们的数据安全。
三者协同:抛出异常标记错误---捕获异常处理错误---释放资源清理现场,形成完整的“错误处理生命周期”。来提高我们程序的可维护性。
一、什么是异常?
---在程序运行的过程中,由于意外情况导致程序发生的异常事件。
比如:
int[] arr = {1,2,3,4};
arr = null;
//空指针异常:NullPointerException
System.out.println(arr[0]);
在java中,把常见的异常情况,都抽象成了对应的异常类型,那么每种异常类型都代表了一种特定的异常情况。
当我们程序出现一种异常情况时,也会创建并抛出一个异常类型对象,这个对象就表示当前程序所出现的问题。
如图,当上述程序运行后,会抛出NullPointerException异常。
空指针异常被抽象为了NullPointerException类型,最后抛出对于的异常对象。
二、异常体系
---常见的异常有哪些?它们直接又该如何分类?
2.1 常见的异常
---在我们的日常练习中,我们遇到过哪些异常呢?
比如:
2.1.1(索引越界异常)
---异常类型:IndexOutOfBoundsException
子类
--ArrayIndexOutOfBoundsException (数组索引越界)
--StringIndexOutOfBoundsException(字符串索引越界)
场景:访问数组、集合或字符串时,索引超出有效范围(如数组长度为 3,却访问索引 3)。
代码演示:
int[] arr = {1, 2, 3};
System.out.println(arr[3]); // 数组最大索引为2,访问3时抛出
2.1.2(算术异常)
---异常类型:ArithmeticException
---数学运算中出现不合理操作,比如: “除数为 0”。
代码演示:
int a = 10 / 0; // 除数为0,抛出异常
2.1.3(类型转换异常)
---异常类型:ClassCastException
---将字符串转换为数字时,字符串格式不符合数字要求。
代码演示:
String str = "abc";
int num = Integer.parseInt(str); // "abc"无法转为int,抛出异常
2.1.4(数字格式异常)
---异常类型:NumberFormatException
---将字符串转换为数字时,字符串格式不符合数字要求。
代码演示:
String str = "abc";
int num = Integer.parseInt(str); // "abc"无法转为int,抛出异常
2.1.5(非法参数异常)
---异常类型:IllegalArgumentException
---方法接收的参数不符合预期(如传递负数给 “年龄” 参数)。
代码演示:
public void setAge(int age) {if (age < 0) {throw new IllegalArgumentException("年龄不能为负数");}
}
以上的异常在我们过去的练习中时常遇到,他们共同归属于运行时异常,在我们的编译阶段不会报错,可以正常编译。
那么,既然有运行时异常,有没有编译时异常呢?
当然有,我们的异常类拥有运行时异常和编译时异常两大体系。
在此之上,异常又和错误同级,被Throwable统治。
让我们一起看一看这个Throwable统治下的异常体系!
2.2 Throwable
---异常体系中的老大哥。
2.2.1 错误VS异常
Error:
--错误;
--程序出现了严重情况;
--程序无法自行处理。
Exception:
--异常;
--可以通过特定方式处理;
--处理后程序可以继续向下正常运行。
注意:
虽然Error和Exception共同构成了异常体系,但我们通常说的异常是指Exception。
2.2.2 异常种类
---编译时异常&&运行时异常
我们平时使用的异常类型都是Exception的子类型,它们把异常划分为了两种:
--编译时异常;
--运行时异常。
首先为了方便大家理解,我先给大家一幅完整的异常体系图:
大家点击异常体系图即可跳转链接,此处可能有些看不清楚,请见谅。
如果链接点不开,也可以私信我领取链接。
借助这幅图,我们便可以很清晰的观察出运行时异常和编译时异常的差别。
编译时异常:
--继承自Exception类;
--编译器在编译期间就会检查这种异常;
--异常发现必须处理,否则程序错误,无法通过编译
运行时异常:
--继承自RuntimeException类及其子类;
--编译器在编译期间不会检查这种异常;
--但是运行期间出现这种异常将会自动抛出。
思考:运行时异常可以通过编译,但是它在运行时是如何被抛出的呢?
三、异常传播
---向上抛出,直到JVM。
如果一个方法中出现了异常的情况,系统默认的处理方式是:自动创建异常对象,并将这个异常对象抛给当前方法的调用者,并一直向上抛出,最终传递给JVM,JVM的默认除了步骤有两步:
--把异常的名称,错误原因及其出现位置输出在控制台;
--程序停止执行。
3.1 代码演示:
public class Test {public static void main(String[] args) {System.out.println("hello");test1();System.out.println("world");}public static void test1(){test2();}public static void test2(){test3();}public static void test3(){//下面代码会抛出异常int a = 1/0;}}
3.2 运行结果:
3.3 代码分析:
--因为ArithmeticException是运行时异常,所以代码可以编译通过;
--程序运行,先输出“hello”,然后一层层调用,最终执行test3方法;
--执行test3时,出现除数为0,系统自动抛出异常Ar...E..;
--代码中没有捕获处理,异常向上传递test2-->test1-->main-->JVM;
--JVM虚拟机拿到异常后,输出相关信息,终止程序。
四、异常抛出
--分为自动抛出和手动抛出
相信大家都见过try...catch()...吧!
当然,我们这篇文章只是了解异常,try..catch是异常处理的内容,这里只做简单了解,下一篇文章再具体讲解。
我们需要知道:
异常,不只是固定的几种,我们也可以创造异常。
就像if判断句一样,我们创造异常的目的,也是为了满足一些条件。
就比如刚刚的年龄抛出异常。
public void setAge(int age) {if (age < 0) {throw new IllegalArgumentException("年龄不能为负数");}
}
此处便抛出了我们创造的异常--“年龄不能为负数”。
而JVM本身会抛出的异常和我们显式创建就是自动抛出和手动抛出。
4.1 自动抛出
---抛出指定好的异常情况
java代码中,出现了提前指定好的异常情况时,代码会自动创建异常对象,并将该异常对象抛出。
例如:上述案例中执行int a=1/0;的时候,代码会自动创建并抛出ArithmeticException类型的异常对象,来表示当前的这种异常情况。(算术异常)
4.2 手动抛出
---在我们的条件下抛出异常
在一些特殊情况下,我们也可以手动创建并抛出异常对象,抛出后系统也会按照默认的方式去处理。
手动抛出异常固定格式:
throw 异常对象;
代码演示:
从键盘录入用户名和密码,如果不是“无敌战神”和“123456”,则主动抛出异常。
public class Test {public static void main(String[] args) {String username;String password;//录入用户名和密码Scanner scanner=new Scanner(System.in);username=scanner.nextLine();password=scanner.nextLine();login(username, password);}//判断登录方法private static void login(String username, String password) {if("无敌战神".equals(username)&&"123456".equals(password)){System.out.println("登录成功");}else {System.out.println("登录错误");//注意要抛出运行时异常throw new RuntimeException("编译异常:登录失败异常");}}
}
运行结果:
注意:
如果抛出的是编译时异常,则编译器会检查,我们无法通过编译。
当然,如果你非要抛出编译时异常。
那么有两种方法解决:
--声明当前方法不对该异常处理,继续抛出异常给上一级;
--主动捕获异常并处理。
这两种方法我们下一篇文章都会讲。
尤其是主动捕获异常,我们见过的老朋友:try...catch..
让我们期待一下!
OK!本篇文章便到此结束!
希望大家能对异常有个了解,为我们学习异常处理打下好的基础。
风浪似海底枯石般尖啸;
心如寒潭月,一半碎成银鳞,一半沉做墨影。
黄沙似星空陨石般卷落;
泪如悬丝星,一半颤着微光,一半缠在网眼。
盼君春归处;
别染坠春泥。