JAVA异常处理机制
1.异常简介
●异常是Java提供的一种识别及响应错误的一致性机制,可以使程序中异常处理代码和正常业务代码分离,提高程序健壮性。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pKvS1eNI-1650275705939)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/101.png)]
●Throwable:Java中所有错误与异常的超类,报错Error和Exception两个子类。
●Error:Error类及其子类是指程序中无法处理的错误(无法通过修改代码逻辑来解决),表示运行应用程序中出现了严重的错误,一般都是JVM出现了问题,常见问题有VirtualMachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)、OutOfMemoryError(内存不足)、StackOverflowError(栈溢出错误)等。
●Exception:程序本身可以捕获并处理的异常,分为运行时异常和编译时异常:
■运行时异常(RunTimeException):Java编译器不会检查此类异常,即使没有throws声明抛出它,也没有trycatch它,也可以编译通过(本身不检查它,当然不知道它存在了),这类异常通常是因为程序逻辑错误引起的,在程序中可以捕获并处理,也可以不处理(有try无catch)。此类异常会由JVM自动抛出并捕获,大多数是由于代码本身由问题造成的(程序本身存在错误)。
▼NullPointerException(空指针异常)
▼IndexOutofBoundsException(数组角标越界)
▼ClassCastException(类型转换异常)
▼InputMismatchException(输入不匹配)
▼ArithmeticException(算数异常)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0mRdav7w-1650275705942)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/106.png)]
■编译时异常(除了RuntimException及其子类之外的所有异常):Java编译器会检查他,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。(往往程序正确,但是外在条件不满足导致引发异常)
▼ClassNotFoundException(没有找到指定类)
▼IOException(IO流异常)
2.受检异常和非受检异常
●受检异常:编译器必须处理的异常:除了RuntimeException及其子类,其余异常都属于受检异常。(那不就是编译时异常么)
●非受检异常:RuntimeException+Error
3.异常处理关键字
●try:用于监听,将要被监听的代码(可能抛出异常的代码)放在try语句块内,当try语句块内发生异常时,就会抛出这个异常。
●catch:用于不过try抛出的异常
●finally:finally语句块总会被执行。主要用于回收try中打开的物理资源
●throw:用于抛出单个异常,在语句中使用
●throws:用在方法名中,声明该方法可能抛出的异常。
4.异常处理机制:抓抛模型
●抛过程:一旦出现了异常,就会在异常处生成一个对应的异常类对象,并将此对象抛出,一旦抛出后,后面的代码不再执行。(可以是系统自动生成的异常对象,也可以手动生成一个异常对象,然后使用throw关键字抛出:throw new RuntimeException(“输入数据非法”))。
●抓过程:异常处理的方式,使用try将可能出现的代码包装起来,生成异常类对象后,和catch的参数进行匹配,一旦处理完成,就跳出粗当前的try-catch结构(哪怕后面还有符合Exception的catch也不看了,所以要考虑catch的前后顺序(子类在前)),继续执行异常出现之后的代码。
●即使catch中又出现了异常/try中有return语句/catch中有return语句,也会先执行finally。
●在try中声明的变量,不能在外面直接用,因为可能没有出现异常所以找不到这个变量。
5.异常处理机制:throws
●throws+异常类型:写在方法的声明处,指明方法可能抛出的异常,一旦方法体执行出现异常,就会在异常代码处生成一个异常类对象,若符合throws的类型,就会将异常抛给调用此方法的方法。异常后面的代码就不再执行(总要有一层来解决这个异常)
●try-catch-finally:真正的解决异常,throws只是将异常抛给了调用者,并没有真正解决
●子类抛出的异常,不大于父类被重写的方法抛出的异常
●如果父类被重写的方法没有throws,则子类只能用try-catch-finally。
6.用户自定义异常类
●继承现有的异常结构:RuntimeException,Exception。
●提供全局变量serialVersionUID(看父类里有啥就抄啥)
●提供重载的构造器
7.Error和Exception的区别是什么
●Error类型的错误通常为虚拟机相关错误,如内存不足,堆栈溢出,编译器不会对这类错误进行检测,Java也不会对这类错误进行捕获,一旦发生,程序就会终止。
●Exception类的错误可以在程序中捕获并处理。
8.JVM是如何处理异常的
●一个方法中如何发生异常,这个方法就会创建一个异常对象,并转交给JVM,该异常对象包含异常名称,异常描述以及异常发生时的应用程序的状态。创建异常对象并转交给JVM的过程称为抛出异常。可能有一系列的方法调用,最终才进入最终抛出异常的方法,这一系列方法调用的有序表叫调用栈。
●JVM会顺着调用栈去查找是否有可以处理异常的代码,如果有则调用异常处理代码。当JVM发现可以处理异常的代码时,会把发生的异常传给他。如果JVM没有找到可以处理该异常的代码块,JVM就会把异常转交给默认的异常处理器(JVM的一部分),默认异常处理器打印出异常信息并终止程序。
9.throw和throws区别
●throws是用在方法声明处的,声明该方法要抛出的异常,可以一次声明多种异常。
●throw关键字用在方法内部,只能用于抛出一种异常,用来抛出方法或代码块的异常。
10.NoClassDefoundError和ClassNotFoundException
●NoClassDefoundError是一个Error类型的异常,是由JVM引起的,不能捕获,通常是由于ClassLoader尝试加载某些类时在内存找不到该类的定义,该动作发生在运行期间,即编译时该类存在,但是运行时找不到了,可能是编译后的class文件被删除了。
●ClassNotFoundException是一个受检异常,需要显式的处理。当类加载到内存的时候,通过存入的路径参数没有找到该类就会抛出该异常。
11.try-catch-finally中哪部分可以省略
●其实一般人都会首先想到finally吧,但这里主要讲的不是这个,而是catch。更严格的说法是,try只适合处理运行时异常,而try+catch适合处理运行时异常+编译时异常。也就是说只用try去处理编译时异常是不能通过编译的,因为编译器规定,编译时异常如果捕获则必须用catch进一步处理,而运行时异常没有。