异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。
在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避免的,比如:客户输入数据的格式,读取文件是否存在,网络是否始终保持通畅等等。
Java异常层次:
Throwable类是JAVA语言所有错误或异常的超类(两个直接子类:Error和Exception)
Java程序在执行过程中所发生的异常事件可分为两类:
Error:
Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。
Exception:
其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:空指针访问、试图读取不存在的文件、网络连接中断。
编译时异常:
在编译某个程序的时候有可能会有这样那样的事情发生,这样的异常就必须在编译的时候处理,如果不处理编译通不过。(Java程序必须显式处理,否则程序就会发生错误,无法通过编译)
运行时异常:
就是程序员所犯的错误,需要回来修改代码(无需显式处理,也可以和编译时异常一起处理)
JVM默认是如何处理异常的?
main函数收到问题后,有两种处理方式
a: 自己将问题处理,然后继续运行
b:自己没有针对的处理方式,只有交给调用main的JVM来处理
JVM有一个默认的异常处理机制,就将该异常进行处理,并将该异常的名称,异常的信息,异常出现的位置打印在了控制台上,同时将程序停止运行
虚拟机处理后,将所有异常信息在控制台打印出来:
异常处理的两种方式
a: try...catch...finally
(try catch
try catch finally
try finally)
try用来检测异常
catch 用来捕获异常
finally 用来释放资源
(当通过try catch 将问题处理了,程序会继续运行)
b: throws
注意:
客户端开发,一般用try catch处理异常;服务端开发,一般都是底层开发,由底层往上抛。
try后面如果跟多个catch,那么小的异常放前面,大的异常放后面(根据多态的原理,如果大的放前面,就会将所有的子类对象接收,后面的catch就没有意义了)
throws的方法处理异常:
定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
throw的概述:
在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw将异常对象抛出
throws和throw的区别Throwable的几个常用方法:
getMessage(); 获取异常信息,返回字符串
toString(); 获取异常类名和异常信息,返回字符串
printStackTrace(); 获取异常名,异常信息以及异常出现在程序中的位置。返回值void)
JVM默认使用第三种这种方式处理异常finally特点:
被finally控制的语句体一定会执行
(特殊情况:在执行到finally之前JVM退出了,比如System.exit(0))
作用: 用于释放资源
面试题1:final、finally、finalize的区别
final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。
面试题2:如果catch里面有return语句,finally里面的代码还会执行吗?如果会,请问是在return前还是return后?
代码示例1:
public class FinallyDemo2 {public static void main(String[] args) {System.out.println(getInt());}public static int getInt() {int a = 10;try {System.out.println(a / 0);a = 20;} catch (ArithmeticException e) {a = 30;return a;/** return a 在程序执行到这一步的时候,这里不是return a 而是 return *30;这个返回路径就形成了* 但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40* 再次回到以前的路径,继续走return 30,形成返回路径之后,这里的a*就不是a变量了,而是常量30*/} finally {a = 40;}}}
代码示例2:
public class FinallyDemo2 {public static void main(String[] args) {System.out.println(getInt());}public static int getInt() {int a = 10;try {System.out.println(a / 0);a = 20;} catch (ArithmeticException e) {a = 30;return a;} finally {a = 40;return a; //如果这样,就又重新形成了一条返回路径,由于只能通过1个 //return返回,所以这里直接返回40}}}
自定义异常
为什么要用自定义异常? 通过名字区分到底是什么异常
继承自Exception或RuntimeException
异常注意事项:
子类抛出的的异常与父类抛出的异常相同或者是父类抛出的异常的子类
子类不能抛出父类没有的异常
如果父类中被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常。如果子类中有异常发生,那么子类只能try,不能throws
如何使用异常处理?
原则:如果该功能内部可以将问题解决,用try,如果处理不了,交由调用者处理,这里用throws
区别:
后续程序需要继续运行就try
后续程序不需要运行用throws