文章目录
异常
异常概述
-
什么是异常?
异常就是编译过程或运行过程中程序出现的不正常的情况; -
java异常体系
概述Throwable
Throwable类
- 所有异常的祖宗类是java.lang.Throwable;
- Throwable类是java语言中所有错误和异常的超类(父类)
- Throwable类的两个子类:Error和Exception(异常)通常用于表示出现异常情况
- Error:表示严重的问题,java程序是无法解决的,合理的应用程序不应该试图捕获。比如硬件存在问题、内存资源不足等问题()
- Exception及其子类都是Throwable形式,表示合理应用程序可能想要捕获的条件
- 除了RuntimeException及其子类、error及其子类,其余都是受检异常,受检异常就是编译期间必须处理的,否则不能通过编译,就更不能正常执行了。
- RuntimeException是在java虚拟机的正常操作期间可以抛出的异常的超类;RuntimeException及其子类是未经检查的异常
ArrayIndexOutBoundsException类
- 异常ArrayIndexOutBoundsException类继承于多个类,最开始继承于Object类、Throwable类
- 异常ArrayIndexOutBoundsException类属于RuntimeException异常
Error和Exception
区别 | Error | Exception |
---|---|---|
概念 | 程序无法处理的,与代码编写者执行的操作无关,无法被捕获 | 运行时错误,可以预料的异常,需要catch捕获然后进行处理 |
常见子类 | OutOfMemoryError 内存溢出(简称OOM) StackOverflowError 栈溢出 | RuntimeException 非受检异常(运行时异常)不强制使用catch捕获,根据实际场景判断 CheckedException 受检异常,必须通过Catch捕获 |
Error
有个OutOfMemoryError的错误,idea设置VM option还是不行,案例连接是:VM option
Exception
概述
java中的异常被分为两大类:编译时异常 和 运行时异常,也被称为 受检异常 和 非受检异常 英文名字是:CheckedException 和 RuntimeException 。
RuntimeException类及其子类被称为运行时异常;
其他的异常都是编译时异常;
受检异常 = 除了 RuntimeException及其子类 和 error及其子类
受检异常与非受检异常
区别 | 受检异常 CheckedException | 非受检异常(运行时异常) RuntimeException |
---|---|---|
概念 | 需要通过Catch捕获的异常 | 不需要调用者显示捕获的异常 |
是否需要处理 | 需要 必须显式处理,否则程序就会发生错误,无法通过编译 | 不需要 无需显式处理,但也可以和编译时异常一样处理 |
处理方法 | Add exception to method signature 表示把这个异常再往上抛 Surround with try/catch 表示使用try/catch捕获 | 无 |
常见异常 | NoSuchFieldException 表示该类没有指定名称抛出来的异常 IllegalAccessException 不允许访问某个类的异常 ClassNotFoundException 类没有找到抛出异常 IOException IO异常 NumberformatException 数值类型的格式错误 FileNotFountException 表示该类没有被找到跑出来的异常 | ArrayIndexOutBoundsException 数组越界异常 NullPointerException 空指针异常 IllegalArgumentException 非法参数异常 NegativeArraySizeException 数组长度为负异常 IllegalStateException 非法状态异常 ClassCastException 类型转换异常 |
处理原因 | 方便调用者接收到该异常清楚知道是什么异常从而方便修改 | — |
最大区别 | 编译器强制执行,表示不受程序控制的异常 | 运行时发生,指示编程错误 |
运行时异常:
// 25 -ThrowableDemo2
//运行时异常,编译阶段不报错,运行后会在控制台输出错误
public static void method(){
int[] arr = {1,2,3};
System.out.println(arr[3]);//java.lang.ArrayIndexOutOfBoundsException: 3
//解决:① 运行后返回程序进行修改;②在编译阶段处理,利用try..catch
}
编译时异常:
// 25-ThrowableDemo2
//编译时异常,案例采用Sting转 日期
public static void method2(){
try {
String s = "2022-2-7";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
System.out.println(d);
//输出结果是 : Mon Feb 07 00:00:00 CST 2022
//也就是异常不一定会出现,只有当String和SimpleDateFormat对象的模式不匹配的时候才会出现异常
}catch(ParseException e){
e.printStackTrace();
}
//直接通过SimpleDateFormat对象.parse方法会报错;处理采用try..catch
//编译时异常,不显示解决,程序无法通过编译,更不能执行。
//编译时异常表示有可能会出现异常,比一定会出现异常。
}
JVM处理异常的默认方式
- 把异常的名称、异常原因及异常出现的位置等信息输出在控制台
- 程序停止执行
案例:
// 25
public class ExceptionDemo1 {
public static void main(String[] args) {
System.out.println("start");
method();
System.out.println("end");
}
public static void method(){
int[] arr = {1,2,3};
System.out.println(arr[3]);
}
}
输出内容:
start
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at
//运行时异常。
itheima25.ExceptionDemo1.method(ExceptionDemo1.java:11)
at itheima25.ExceptionDemo1.main(ExceptionDemo1.java:6)
异常的名称 = java.lang.ArrayIndexOutOfBoundsException
异常的原因 = 3
异常出现的位置 = ExceptionDemo1.java:11
异常处理之try…catch
自己处理异常的原因:程序出现异常的时候,由于JVM(java虚拟机)默认处理方式会将程序在问题处停下,而在实际开发中程序的某一部分出现问题时,不应该影响后续的执行。
程序出现问题,有两种实现方案:try…catch 和 throws。
格式:
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
执行流程:
①程序从try里面的代码开始执行
②
出现异常,会自动生成一个异常类对象
‾
\underline{出现异常,会自动生成一个异常类对象}
出现异常,会自动生成一个异常类对象,该异常类对象将被提交给java运行时系统
③当java运行时系统接收到异常对象时,会到catch中去找匹配的异常类,找到后进行异常的处理
④执行完毕之后,程序还可以继续往下执行
案例:
// 25
// try..catch案例
public class ExceptionDemo2 {
public static void main(String[] args) {
System.out.println("start");
method();
System.out.println("end");
}
public static void method(){
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
//这里出现异常然后创建了对象 new ArrayIndexOutBoundsException();
//将该对象提交给java运行时系统
}catch(ArrayIndexOutOfBoundsException e){//异常类名 变量名(对象名)
//这里的异常类名就是 数组越界后 JVM默认处理方式输出的类名
// System.out.println("数组的索引溢出");
//一般工程中不采用这种形式,都是会弹出一个页面,
//或者使用对象.printStackTrace()
e.printStackTrace();
/*java.lang.ArrayIndexOutOfBoundsException: 3
at itheima25.ExceptionDemo2.method(ExceptionDemo2.java:13)
at itheima25.ExceptionDemo2.main(ExceptionDemo2.java:7)*/
//输出结果是 上述内容,和 不加try..catch一样
// 但是不同的是 添加try.catch 后续的代码会继续执行,而采用JVM默认异常处理模式 输出上述内容,程序运行停止
}
}
}
Throwable的成员方法
Throwable是所有错误和异常的祖宗类,只要属于这个体系的,都可以使用它的成员方法。
案例采用:ArrayIndexOutBoundsException
方法名 | 说明 | 案例 |
---|---|---|
public String getMessage() | 返回此throwable的详细消息字符串 | 输出 3 异常的原因 |
public String toString() | 返回此throwable可抛出的简短描述 包括异常类名、异常原因 | java.lang.ArrayIndexOutOfBoundsException: 3 异常类名、异常原因 |
public void printStackTrace() | 把异常的错误信息输出在控制台 输出包含异常类名、原因、位置信息 | java.lang.ArrayIndexOutOfBoundsException: 3 at itheima25.ThrowableDemo.method(ThrowableDemo.java:14) at itheima25.ThrowableDemo.main(ThrowableDemo.java:8) 输出异常类名、原因、位置 |
下述内容都在try…catch中的catch部分。
e.getMessage()
System.out.println(e.getMessage());
// 输出结果是 3
// 而不是视频中的 Index 3 out of bound for length 3
//输出异常的原因
// 输出不同可能是jdk版本不一样的原因。
e.toString()
System.out.println(e.toString());
//输出内容 = java.lang.ArrayIndexOutOfBoundsException: 3
包括异常类名、异常原因
e.printStackTrace()
e.printStackTrace();
输出包含异常的类名、原因、位置信息
/*
java.lang.ArrayIndexOutOfBoundsException: 3
at itheima25.ThrowableDemo.method(ThrowableDemo.java:14)
at itheima25.ThrowableDemo.main(ThrowableDemo.java:8)
*/
案例:
// 25
// throwable 的三个常用方法
// getMessage、toString、printStackTrace;
public class ThrowableDemo {
public static void main(String[] args) {
System.out.println("start");
method();
System.out.println("end");
}
public static void method(){
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
}catch(ArrayIndexOutOfBoundsException e){
// getMessage()
System.out.println(e.getMessage());
//输出结果是 3 而不是视频中的 Index 3 out of bound for length 3
//输出异常的原因
System.out.println(e.toString());
//输出内容 = java.lang.ArrayIndexOutOfBoundsException: 3
// 包括异常类名、异常原因
e.printStackTrace();
//输出包含异常的类名、原因、位置信息
/*
java.lang.ArrayIndexOutOfBoundsException: 3
at itheima25.ThrowableDemo.method(ThrowableDemo.java:14)
at itheima25.ThrowableDemo.main(ThrowableDemo.java:8)
*/
}
}
}
Throws异常处理
原因:
通过try…catch…可以对异常进行处理,但并不是所有的情况我们都有权限进行异常的处理,处理不了的时候,需要采用java提供的throws处理方案
格式:
throws 异常类名;
这个格式是跟在方法的括号后面的。
// 也就是:
public static void 方法名() throws 异常类名{}
异常处理:
①编译时异常必须要进行处理。两种方案:try…catch 或者 throws 如果采用throws这种方案,将来谁调用谁处理
②运行时异常可以不处理。出现问题后,需要我们回来修改代码
案例:
//28
public class ThrowsableDemo {
public static void main(String[] args) {
System.out.println("start");
// method();
try {
method2();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("end");
}
//编译时异常
public static void method2() throws ParseException {
String s = "2022-2-8";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
//点击alt+enter 弹出窗口选择 Add exception to method signature
//会在方法名的括号后面加上 throws ParseException
//这种方式并没有真正的解决异常,要先解决还是得通过try..catch
System.out.println(d);
//输出 Tue Feb 08 00:00:00 CST 2022
}
//运行时异常
public static void method() throws ArrayIndexOutOfBoundsException{
int[] arr = {1,2,3};
System.out.println(arr[3]);
// 这里会报运行时异常,可以通过try..catch..解决
// 并没有解决异常,只是将异常抛出
}
}
自定义异常throw
概述
自定义异常类格式:
public class 异常类名 extends Exception{
无参构造方法;
有参构造方法;
}
自定义异常类
// 28-test2
public class ScoreException extends Exception {
public ScoreException(){}
public ScoreException(String message){
super(message);
//这样写的原因是:
按下ctrl + b 跟进,(这些传递都是构造方法进行的)
把ScoreException类中的message传到Exception类中
===》把Exception类中的message传到Throwable类中,
message就传递给了detailmessage,
detailmessage是Throwable的成员变量,可以通过getMessage方法得到、也可以通过printStackTrace方法得到。
}
}
异常的使用
手动抛出异常 throw new 异常名();或者 throw new 异常名(参数);
案例:
// 28-test2
//异常的使用:手动抛出异常 throw new 异常名();或者 throw new 异常名(参数);
public class Teacher {
public void checkScore(int score) throws ScoreException {
if(score <0 || score >100){
* throw new ScoreException();
// 抛出的异常 不显示异常的原因
// 通过throw抛出异常对象,如果自定义异常继承的是RuntimeException,则异常的抛出可以用throw抛出,也可以不用throw抛出
* throw new ScoreException("分数超过范围,应该在0-100之间");
// 抛出的异常 会显示异常的原因,就是上述括号中的文字
}else{
System.out.println("分数正确");
}
}
}
测试代码:
// 28-test2
public class TeacherDemo {
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();
}
** 抛出异常采用无参构造方法 throw new ScoreException();
当分数出现异常的时候,会在控制台输出异常类名、异常位置等信息。不会输出异常原因。
/*itheima28.test2.ScoreException
at itheima28.test2.Teacher.checkScore(Teacher.java:6)
at itheima28.test2.TeacherDemo.main(TeacherDemo.java:13)
*/
** 抛出异常采用有参构造方法 throw new ScoreException(参数);
当分数出现异常的时候,会在控制台输出异常类名、异常位置等信息。会输出异常原因,也就是自定义异常ScoreException中的参数。
/*
itheima28.test2.ScoreException: 分数超过范围,应该在0-100之间
at itheima28.test2.Teacher.checkScore(Teacher.java:8)
at itheima28.test2.TeacherDemo.main(TeacherDemo.java:13)
*/
}
}
Throws 和 Throw 的区别
区别 | Throws | Throw |
---|---|---|
位置 | 用在方法声明后面,跟的是异常类名 | 用在方法体内,跟的是异常对象名 |
异常的处理对象 | 表示抛出异常,由该方法的调用者来处理 | 表示抛出异常,由方法体内的语句处理 |
是否一定存在 | 否,表示出现异常的一种可能性,并不一定会发生这些异常 | 是,执行throw一定抛出了某种异常 |
理解xhj:
- 位置:
public static void 方法名() throws 异常类名{}
位于方法声明之后
throw new 异常类名();
在方法体内,跟着异常类对象名 = new 异常类名()
- 异常处理的对象:
throws : 调用此方法的时候处理
try{
方法名();
}catch(异常类 e){
e.printStackTrace();
}
throw:在方法内进行处理
if(score > 100 || score < 0){
throw new 异常类名("字符串,表示异常产生的原因描述,方便编程人员看");
}
else{
System.out.println("输入内容正确");
}