1.异常的概念
Java中将程序执行过程中发生的不正常的行为称为异常
比较常见的异常如下:
2.异常的体系结构
Throwable:是异常体系的最顶层的类,它有两个重要的子类,:Error 和 Exception
Exception:我们经常说的异常就是Exception,此类问题可以通过代码进行处理从而使程序可以继续往下运行
Error:指的是Java虚拟机无法解决的严重问题,这类问题就比较严重了,一旦发生想要挽回就很困难了,就像人得了不治之症
异常体系的结构图大致如下:
异常根据发生的时机不同分为编译时异常(受检查异常)和运行时异常(非受检查异常)
RuntimeException以及其子类对应的异常都是运行时异常
注:写代码的时候出现的语法错误不能称之为异常
3.异常的处理
处理异常的两个思想:
LBYL:在操作之前进行充分的检查
EAFP:先进行操作,在遇到问题的时候再来处理
异常处理的核心思想就是EAFP
3.1抛出异常
首先可定是要找出异常的位置
关键字:throw
语法如下;
throw new xxxException("产生异常的原因")
比如写一个获取数组元素的方法
public static int getElement(int[] arr,int index) { if(arr==null) { throw new NullPointerException("数组为空"); } if(index<0||index>=arr.length) { throw new ArrayIndexOutOfBoundsException("下标非法"); } return arr[index]; }
注:
- throw必须是在方法内部
- 抛出的对象必须是Exception类或者其子类对象
- 如果抛出的是RuntimeException类或者其子类(即运行时异常),可以交给JVM处理
- 如果抛出的是编译时异常,需要自己处理,否则代码无法通过编译
- 异常一旦抛出,后面的代码便不会再执行
3.2处理异常
主要有两种方式throws和try-catch
3.2.1throws
throws是声明异常,当方法抛出编译时异常时使用throws将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常
语法如下:
方法返回值 方法名() throws 异常类型1,异常类型2{......}
之前文章介绍对象进行比较和克隆操作常用的接口的时候有出现过这种用法
原文链接抽象类和接口
使用注意:
- throws位置是在方法的参数列表后
- 声明的异常必须是Exception类或者其子类
- throws后面可以有多个异常,中间用逗号隔开即可,如果是有父子关系的,声明父类即可
- 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出
throw和throws很相像,二者之间的区别需要注意
throw | throws |
在方法内使用 |
跟在方法声明后面 |
一个throw只能抛出一个异常 |
后面可以跟多个异常类名 |
抛出的异常由方法内的语句处理 |
抛出的异常由方法的调用者处理 |
执行throw是一定出现了某种异常 |
表示有出现异常的可能性,并不一定就会出现这些异常 |
3.2.2try-catch
try-catch就是真正的对异常进行处理,语法如下:
try { //可能出现异常的代码放在此处 } catch(xxxException e) { //若try抛出的异常被catch捕获到,在此处进行处理 }
try后面可以有多个catch,catch括号中可以写多个异常类型,中间使用“|”隔开
还是以上面的获取数组元素的方法为例,对其进行修改:
public static int getElement(int[] arr,int index) { return arr[index]; } //main方法中使用try-catch public static void main(String[] args) { int[] arr=new int[]{1,2,3,4,5}; try { getElement(null,1); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("下标越界"); } catch(NullPointerException e) { System.out.println("空数组"); } }
注意:
try块内抛出异常位置之后的代码不会被执行
try抛出的异常需要被catch捕获才能处理,如果抛出的异常没有被捕获,则会继续向外抛出,直至JVM中断程序
如果异常之间具有父子关系,一定是子类异常在前先被捕获,父类异常后被捕获
使用try-catch后只会打印自己代码块内的信息,上图中也可以看到,想要异常信息尽可能完整,可使用printStackTrace()方法
此外还有一个关键字:finally
这个关键字需要记住的是:不管程序是否发生异常,finally中的语句都会被执行
基于此特点,所以finally一般是用来进行一些资源清理的扫尾工作
还有,不建议在finally中放入return语句,比如下面代码
public static int fc() { try { retrun 1; } catch(ArithmeticException e) { System.out.println("算数异常"); } finally { return 10; } }
结果返回的是10,try中的1因为fianlly的存在是无法返回的
3.3异常的处理流程
在JVM中有一块内存空间叫做"虚拟机栈" ,这块空间是专门用来存储方法之间的调用关系的,这种调用关系用“调用栈”来描述
当代码中出现异常而又没有对应的处理方式的时候,就会沿着调用栈向上传递,直到传递到JVM终止程序
异常的处理流程如下:
- 优先执行try中的代码抛出异常
- 若catch捕获到异常,则处理异常,否则向上传递
- 如果一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止
4.自定义异常
虽然Java本身就已经有很多异常类,但在实际的开发中仍然会遇到一些Java中没有包含的异常,此时就需要自定义异常
具体实现方式如下:
- 自定义一个类,继承Exception(编译时异常)或RunTimeException(运行时异常)
- 类里面实现一个带有String类型参数的构造方法,String是为了说明出现异常的原因
到此这篇关于JavaSE详细讲解异常语法的文章就介绍到这了,更多相关Java异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!