异常在表现形式上分两种:
1、运行时异常
语法没有错误,编译通过了,但是运行起来后程序在控制台报错,并停止运行。
2、编译时异常
他是语法没有错误,但是编译不通过。用鼠标指过去以后,会提示:有未处理的异常,后面跟异常的名字。
1、异常的分类
NullPointerException
空指针异常 --- 企图调用一个空对象的属性或方法
ArrayIndexOutofBoundsException
数组下标越界异常
ClassCastException
类型转换异常
这么多异常类,先人在设计的时候都是按照封装继承的方式进行设计,形成了一个树形结构图。
最顶级的:Throwable类
第二级: Exception Error
Exception -- 异常
Error -- 错误
他们都是我们程序在语法正确的情况下,在运行期或编译期出现的问题。但是两者的严重层度和解决方案不一样。
Exception更多的是指可以用代码去解决的问题;
Error往往不是代码级别的问题,往往是运行环境或硬件问题。
Exception和Error都是Throwable的子类,所以他们都可以抛出,当然也都可以catch。
第三层:Exception的子类
RuntimeException --- 它和它的子类是运行时异常;--- 也就是在编译期不检查是否处理,没处理的话运行时报错。
非RuntimeException --- 它们和它们的子类是编译时异常;--- 要求编译期必须解决,否则编译不通过。
2、异常的传播机制
首先要认知报错信息,要开心,要能够从中获取正确的有帮助的信息:
2-1、发生在哪个线程当中 --- 这个目前不需要,因为单线程;
2-2、发生了什么异常 --- 看异常的名字,对常见异常要逐渐形成经验性的解决方案;不熟悉的要学会查询(APIDOC文档,百度,Google)
2-3、发生在哪里? --- 从上往下找第一行你写的代码
为什么会有多个异常发生位置?
这是因为异常的传播机制。在程序运行阶段,一旦发生了异常,那么JVM会自动产生一个对应类型的异常对象,把本次发生异常的基本信息封装进去。然后在当前代码处,查看是否有该异常的处理方案;如果没有,那么JVM会提前结束这个方法,然后带着异常对象返回方法调用处。接着,在方法调用处查看是否有该异常的处理方案,如果没有,那么再结束这个方法,返回它的调用处。如此执行下去,直到main方法如果也没有解决,那么终止main方法,打印异常信息在控制台。而main方法的终止,程序肯定也终止了。
这个异常的传播机制又告诉了我们额外的两个知识点:
1、方法结束的方式不仅仅是遇到方法的结束"}" 或 “return”关键字;遇到未处理的异常,方法也会结束。而所有的结束,都是返回方法调用处!
2、如果要求发生异常,程序不结束,那么我们其实是可以在异常的传播路径的任意位置进行处理的。当然,不同的位置,效果有差异。