Java异常处理:
Java的异常处理机制可以让程序具有良好的容错性 让程序更加健壮。当出现意外的时候,Java会自动生成一个Exception对象来通知程序 从而将 实现代码 和 错误代码分离,提供更好的可读性。
1. 分类:Java中把所有非正常情况分为两种:异常(Exception) 和 错误(Error),他们都继承Throwable父类。(可通过查看API学习)
- 分类
- 错误(Error):一般无法恢复或不可能捕获,通常应用程序无法处理这些错误。(一般指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接接受失败等。)
- 异常(Exception):
- 编译期异常:不属于所有的RuntimeException类及其子类的实例。(必须显示处理)
- 运行期异常:所有的RuntimeException类及其子类的实例。(无需显示处理)
2. Java中JVM的默认处理异常机制:
当Java代码中当出现意外时,main函数收到这个问题时,有两种处理方式:
- 方式一: 自己将该问题处理,然后继续运行。
- 方式二:自己没有针对的处理方式,只有交给调用main的jvm来处理,其中JVM有一个默认的异常处理机制,就将该异常进行处理,并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上,同时将程序停止运行。
处理结果:展示异常,结束运行。
3. 常见处理方式和语法:
捕获异常:try …catch 和 抛出异常:throws。
try…catch处理异常的基本格式:
try {
可能出现问题的代码 ;
}catch(异常名 变量名){
针对问题的处理 ;
}finally{
释放资源;
}
多异常捕获:
try {
可能出现问题的代码 ;
}catch(异常名1 | 异常名2 | .... 变量名){
对异常的处理方案 ;
}finally{
释放资源;
}
- 注意
- try中的代码越少越好,把有问题的语句放在try块里。
- catch中要做处理,哪怕是一条输出语句也可以。(不能空处理,不能将异常信息隐藏)
- 通常情况下,如果try块被执行一次,try块后只有一个catch块会被执行,绝不可能有多个catch块被执行。除非在循环中使用continue语句。
- 尽量明确异常类型,不要直接用Exception异常。
- 父类异常必须在子类异常的后面,否则JVM会直接捕获父类异常而忽略子类异常。
- 多异常捕获的时候,这些异常之间必须是平级关系。
为什么通常情况下,如果try块被执行一次,try块后只有一个catch块会被执行?
原理解释:
当程序进入负责异常处理的catch块时,系统生成的异常对象ex将会传给catch块后的异常形参,从而允许catch块通过该对象来获取异常的详细信息。
try块后面不同的catch块提供不同的异常处理方式。
当系统发生不同情况的意外,系统会生成不同的异常,Java运行时,就根据该异常对象所属的异常类来决定使用哪个catch块来处理异常。
4.异常处理Throwable常用方法:
方法 | 功能 |
getMessage(): | 获取异常信息,返回字符串 |
toString(): | 获取异常类名和异常信息,返回字符串 |
printStackTrace(): | 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void |
5.关键字:throws
- 前提:定义功能方法时,需要把出现的问题暴露出来让调用者去处理。
- 用法:在本方法中出现异常,若在本方法中不想处理可以在本方法签名后面使用throws+异常类进行抛出。
- 编译器异常调用者必须显示处理。
- 运行期异常调用者可以不处理。
- throws可以连续抛出多个异常。
6.关键字:throw
- 前提:在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
- 用法:用在方法体内,后跟异常对象名,只能抛出一个异常对象名。
- 表示抛出异常,由方法体内的语句处理。
- throw抛出了异常,执行throw则一定是抛出了某种异常。
- 如何处理:
- 如果功能内部可以将异常处理 就用try。。catch处理。
- 如果处理不了就用throws抛出,让调用者处理该异常。
throws和throw的区别:
- throws
- 用在方法声明后面,跟的是异常类名
- 可以跟多个异常类名,用逗号隔开
- 表示抛出异常,由该方法的调用者来处理
- throws表示出现异常的一种可能性,并不一定会发生这些异常
- throw
- 用在方法体内,跟的是异常对象名
- 只能抛出一个异常对象名
- 这个异常对象可以是编译期异常对象,可以是运行期异常对象。表示抛出异常,由方法体内的语句处理
- throw则是抛出了异常,执行throw则一定抛出了某种异常
7.关键字:finally
- finally的特点:
- 被finally控制的语句体一定会执行(前提 JVM没有停止)。
- 特殊情况:在执行到finally之前JVM退出了(比如System.exit(0))
- finally的作用:
- 用于释放资源。
try {
可能出现问题的代码 ;
}catch(异常名 变量名){
针对问题的处理 ;
}finally{
释放资源;
}
思考题:如果catch里面有return语句或者exit(0)语句,请问finally的代码将会怎么执行?
解答:
①当catch块里有exit()时,程序将不再执行final块的内容。
②当catch快里有return语句时,final语句将在return语句前面一步执行,再去执行catch块的return语句。
③当final和catch块里都有return语句时候,会执行final块的return语句。不会再去执行catch块的return语句。只能执行一条return语句。
final,finally和finalize的区别
- final: 是一个状态修饰符, 可以用来修饰类 , 变量 , 成员方法。
- 被修饰的类不能被子类继承, 修饰的变量其实是一个常量不能被再次赋值。
- 被修饰的类不能被子类继承, 修饰的变量其实是一个常量不能被再次赋值。
- 修饰的方法不能被子类重写。
- finally:用在try…catch…语句中 , 作用: 释放资源 . 特点: 始终被执行(JVM不能退出)。
- finalize: Obejct类中的一个方法,用来回收垃圾。
8. 自定义异常:
自定义异常概述:
因为在以后的开发过程中,我们可能会遇到各种问题,而JDK不可能针对每一种问题都给出具体的异常类与之对应。为了满足需求,我们就需要自定义异常。
- 异常注意事项(针对编译期异常):
- 子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类,或者子类不抛出异常也是可以的。
- 如果父类的方法没有抛出过异常,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能捕获try,不能throws。
自定义异常:
public class Myexception extends Exception{
public Myexception(String s) {
super(s);
}
}
自定义异常应用实例:
public class Test1 {
public static void main(String[] args) throws Myexception {
System.out.println("请输入考试成绩:");
Scanner sc = new Scanner(System.in);
int grade = sc.nextInt();
if(grade>100 || grade<0){
throw new Myexception("成绩录入有问题!");
}else {
System.out.println("成绩录入合格!");
System.out.println(grade);
}
}
}