,史上最全的教程来啦~)
创作不易如果觉得这篇文章对你有帮助欢迎各位老铁点个赞呗您的支持是我创作的最大动力文章目录1 前言2 什么是异常3 异常的分类3.1 异常的类图结构3.2 异常的分类4 异常的处理4.1 异常捕获处理4.1.1 try、catch和finally4.1.2 异常捕获处理4.1.3 异常的捕获顺序4.2 throws抛出处理4.3 getMessage()和printStackTrace()4.4 方法覆盖中的异常处理5 异常相关的面试题5.1 谈谈你Java异常处理机制的理解5.2 throw 和 throws 的区别5.3 final、finally、finalize 的区别5.4 Java中异常分为哪些种类5.5 error和exception的区别5.6 说出最常见的5个RuntimeException5.7 调用下面的方法得到的返回值是什么5.8 java 中如何编写自定义异常6 总结1 前言Java中的Exception也是很重要的一部分虽然经常使用Exception但是基础知识比较零散这里笔者也做一下总结吧有利于以后形成良好的知识体系。2 什么是异常定义在程序运行过程中出现的错误称为异常。异常就是程序运行过程中出现了不正常现象导致程序的中断。在Java中把各种异常现象进行了抽象形成了异常类。3 异常的分类3.1 异常的类图结构先来整体认识下异常的类图结构3.2 异常的分类异常主要分为错误、一般性异常受控异常、运行时异常非受控异常错误如果应用程序出现了Error那么将无法恢复只能重新启动应用程序最典型的Error的异常是OutOfMemoryError受控异常这种异常属于一般性异常出现了这种异常必须显示的处理不显示处理java程序将无法编译通过。编译器强制普通异常必须try…catch处理或用throws声明继续抛给上层调用方法处理所以普通异常也称为checked异常。非受控异常非受控异常也即是运行时异常RuntimeException这种系统异常可以处理也可以不处理所以编译器不强制用try…catch处理或用throws声明所以系统异常也称为unchecked异常。此种异常可以不用显示的处理例如被0除异常java没有要求我们一定要处理 当出现这种异常时肯定是程序员的问题也就是说健壮的程序一般不会出现这种系统异常。4 异常的处理运行时异常系统异常不需要预处理通过规范的代码可以避免产生这种异常受检异常编译时异常必须预处理否则编译报错有两种预处理方式 :捕获处理抛出处理4.1 异常捕获处理4.1.1 try、catch和finally异常的捕获和处理需要采用try和catch来处理具体格式如下try{}catch(OneExceptione){}catch(TwoExceptione){}finally{}try中包含了可能产生异常的代码try后面是catchcatch可以有一个或多个catch中是需要捕获的异常当try中的代码出现异常时出现异常下面的代码不会执行马上会跳转到相应的catch语句块中如果没有异常不会跳转到catch中finally表示不管是出现异常还是没有出现异常finally里的代码都执行finally和catch可以分开使用但finally必须和try一块使用如下格式使用finally也是正确的try{}finally{}4.1.2 异常捕获处理异常捕获处理详细说明privatestaticvoidtestException2(){try{//1、对可能产生异常的代码进行检视//2、如果try代码块的某条语句产生了异常, 就立即跳转到catch子句执行, try代码块后面的代码不再执行//3、try代码块可能会有多个受检异常需要预处理, 可以通过多个catch子句分别捕获}catch(异常类型1e1){//捕获异常类型1的异常, 进行处理//在开发阶段, 一般的处理方式要么获得异常信息, 要么打印异常栈跟踪信息(e1.printStackTrace())//在部署后, 如果有异常, 一般把异常信息打印到日志文件中, 如logger.error(e1.getMessage());}catch(异常类型2e1){//捕获异常类型2的异常, 进行处理//如果捕获的异常类型有继承关系, 应该先捕获子异常再捕获父异常//如果没有继承关系, catch子句没有先后顺序}finally{//不管是否产生了异常, finally子句总是会执行//一般情况下, 会在finally子句中释放系统资源}}【代码示例】privatestaticvoidtestException3(){inti1100;inti20;//try里是可能出现异常的代码try{//当出现被0除异常时程序流程会执行到“catch(ArithmeticException arithmeticException)”语句这里是运行是异常编译可以通过//被0除表达式以下的语句永远不会执行inti3i1/i2;//永远不会执行System.out.println(i3);//采用catch可以拦截异常//arithmeticException代表了一个ArithmeticException类型的局部变量//采用arithmeticException主要是来接收java异常体系给我们new的ArithmeticException对象//采用arithmeticException可以拿到更详细的异常信息}catch(ArithmeticExceptionarithmeticException){System.out.println(被0除了);arithmeticException.printStackTrace();}}执行结果4.1.3 异常的捕获顺序异常的捕获一般按照由小到大的顺序也就是先截获子异常再截获父异常以上代码分析将IOException放到前面会出现编译问题因为IOException是FileNotFoundException的父类所以截获了IOException异常后IOException的子异常都不会执行到所以再次截获FileNotFoundException没有任何意义异常的截获一般按照由小到大的顺序也就是先截获子异常再截获父异常。正确的捕获方式try{FileInputStreamfisnewFileInputStream(test.txt);fis.close();}catch(FileNotFoundExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}这里只是为了说明捕获顺序实际中关闭流资源fis.close()是在finally语句块中处理的。4.2 throws抛出处理在定义方法时如果方法体中有受检编译时异常需要预处理可以捕获处理也可以抛出处理。处理异常时使用throws抛出处理谁调用这个方法谁负责处理该异常在定义方法时把异常抛出就是为了提醒方法的使用者有异常需要预处理在处理异常时是选择捕获处理还是抛出处理一般情况下在调用其他方法时如果被调用的方法有受检编译时异常需要预处理选择捕获处理因为你调用了方法 你负责处理该异常。在定义方法时如果方法体中有受检异常需要预处理可以选择捕获也可以选择抛出处理。如果方法体中通过throw语句抛出了一个异常对象所在的方法应该使用throws声明该异常。4.3 getMessage()和printStackTrace()如何取得异常对象的具体信息常用的方法主要有两种获取异常描述信息使用异常对象的getMessage()方法通常用于打印日志时取得异常的堆栈信息使用异常对象的printStackTrace()方法比较适合于程序调试阶段4.4 方法覆盖中的异常处理方法覆盖(重写)规则方法签名必须相同方法名与参数列表就是方法签名方法的返回值类型可以相同 子类方法的返回值类型也可以是父类方法返回值类型的子类型子类方法的访问权限可以更宽泛(更大)a、如果父类方法使用public修饰子类方法只能是public修饰b、如果父类方法使用protected修饰子类方法可以是protected或者public修饰子类方法的异常要比父类方法的异常更小a、如果父类方法没有抛出异常子类重写后也不能抛出异常b、如果父类方法抛出了异常子类方法可以抛出相同的异常也可以抛出父类异常的子异常也可以不抛出异常代码示例/** * 异常处理示例 * 子类方法的异常要比父类方法的异常更小 * a、如果父类方法没有抛出异常子类重写后也不能抛出异常 * b、如果父类方法抛出了异常子类方法可以抛出相同的异常也可以抛出父类异常的子异常也可以不抛出异常 */publicclassExceptionClass2{publicstaticvoidmain(String[]args){}classUserNotFoundExceptionextendsException{}/** * 定义一个接口里面有一个抽象login方法并且抛出了UserNotFoundException异常 */interfaceUserManager{voidlogin(Stringusername,Stringpassword)throwsUserNotFoundException;}/** * 正确写法这里可以抛出UserNotFoundException异常也可以不抛出异常 */classUserManagerImpl1implementsUserManager{publicvoidlogin(Stringusername,Stringpassword)throwsUserNotFoundException{}}/** * 不正确因为UserManager接口中login()方法没有要求抛出PasswordFailureException异常 * 子类异常不能超出父类的异常范围 */classUserManagerImpl2implementsUserManager{publicvoidlogin(Stringusername,Stringpassword)throwsUserNotFoundException,PasswordFailureException{}}/** * 正确因为MyException是UserNotFoundException子类 * MyException异常没有超出接口的要求 */classUserManagerImpl3implementsUserManager{publicvoidlogin(Stringusername,Stringpassword)throwsUserNotFoundException,MyException{}}classPasswordFailureExceptionextendsException{}classMyExceptionextendsUserNotFoundException{}}5 异常相关的面试题5.1 谈谈你Java异常处理机制的理解Java对异常进行了分类不同类型的异常分别用不同的Java类表示所有异常的根类为 java.lang.ThrowableThrowable下面又派生了两个子类Error和Exception。Error表示应用程序本身无法克服和恢复的一种严重问题。Exception表示程序还能够克服和恢复的问题其中又分为系统异常和普通异常。系统异常系统异常是软件本身缺陷所导致的问题也就是软件开发人员考虑不周所导致的问题软件使用者无法克服和恢复这种问题但在这种问题下还可以让软件系统继续运行或者让软件死掉例如数组下标越界ArrayIndexOutOfBoundsException空指针异常NullPointerException、类转换异常ClassCastException。普通异常普通异常是运行环境的变化或异常所导致的问题是用户能够克服的问题例如网络断线硬盘空间不够发生这样的异常后程序不应该死掉。Java为系统异常和普通异常提供了不同的解决方案编译器强制普通异常必须try…catch处理或用throws声明继续抛给上层调用方法处理所以普通异常也称为checked异常而系统异常可以处理也可以不处理所以编译器不强制用try…catch处理或用throws声明所以系统异常也称为unchecked异常。5.2 throw 和 throws 的区别throwthrow 语句用在方法体内表示抛出异常由方法体内的语句处理。throw是具体向外抛出异常的动作所以它抛出的是一个异常实例执行throw一定是抛出了某种异常。throw一般用于抛出自定义异常。throwsthrows语句是用在方法声明后面表示如果抛出异常由该方法的调用者来进行异常的处理。throws主要是声明这个方法会抛出某种类型的异常让它的使用者要知道需要捕获的异常的类型。throws表示出现异常的一种可能性并不一定会发生这种异常。5.3 final、finally、finalize 的区别final用于声明属性方法和类分别表示属性不可变方法不可覆盖被其修饰的类不可继承。finally异常处理语句结构的一部分表示总是执行。finalizefinalize 是Object 类的一个方法所以Java对象都有这个方法当某Java对象没有更多的引用指向的时候会被垃圾回收器回收该对象被回收之前由垃圾回收器来负责调用此方法通常在该方法中进行回收前的准备工作。该方法更像是一个对象生命周期的临终方法当该方法被系统调用则代表该对象即将“死亡”但是需要注意的是我们主动行为上去调用该方法并不会导致该对象“死亡”这是一个被动的方法其实就是回调方法不需要我们调用。5.4 Java中异常分为哪些种类按照异常需要处理的时机分为编译时异常(也叫受控异常)也叫 CheckedException和运行时异常(也叫非受控异常)也叫 UnCheckedException。Java认为Checked异常都是可以被处理的异常所以Java程序必须显式处理Checked异常。如果程序没有处理Checked 异常该程序在编译时就会发生错误无法编译。这体现了Java 的设计哲学没有完善错误处理的代码根本没有机会被执行。对Checked异常处理方法有两种当前方法知道如何处理该异常则用try…catch块来处理该异常。当前方法不知道如何处理则在定义该方法时声明抛出该异常。对于运行时异常只有当代码在运行时才发行的异常编译的时候不需要try…catch。比如除数是0和数组下标越界等其产生频繁处理麻烦若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。5.5 error和exception的区别Error类和Exception类的父类都是Throwable类他们的区别如下Error类一般是指与虚拟机相关的问题如系统崩溃虚拟机错误内存空间不足方法调用栈溢出等。对于这类错误的导致的应用程序中断仅靠程序本身无法恢复和预防遇到这样的错误建议让程序终止。Exception类表示程序可以处理的异常可以捕获且可能恢复。这种异常是由与程序设计的不完善而出现的问题遇到这类异常应该尽可能处理异常使程序恢复运行而不应该随意终止异常。Exception类又分为未检查异常UnCheckedException和受检查的异常(CheckedException)。运行时异常ArithmeticExceptionIllegalArgumentException编译能通过但是一运行就终止了程序不会处理运行时异常出现这类异常程序会终止。而受检查的异常要么用 try…catch 捕获要么用throws字句声明抛出交给它的父类处理否则编译不会通过。5.6 说出最常见的5个RuntimeException常见的异常有java.lang.NullPointerException 空指针异常出现原因调用了未经初始化的对象或者是不存在的对象java.lang.ClassCastException 数据类型转换异常java.lang.ClassNotFoundException 指定的类找不到出现原因类的名称和路径加载错误通常都是程序试图通过字符串来加载某个类时可能引发异常java.lang.NoSuchMethodException 方法不存在异常java.lang.NumberFormatException 字符串转换为数字异常出现原因字符型数据中包含非数字型字符java.lang.IndexOutOfBoundsException 数组角标越界异常常见于操作数组对象时发生java.lang.IllegalArgumentException 方法传递参数错误java.lang.NoClassDefFoundException 未找到类定义错误SQLException SQL 异常常见于操作数据库时的 SQL 语句错误java.lang.InstantiationException 实例化异常5.7 调用下面的方法得到的返回值是什么这个问题估计大神也可能回答错误。publicstaticintgetNum(){try{inta1/0;return1;}catch(Exceptione){return2;}finally{return3;}}上述代码调用后返回的结果是3代码分析如下publicstaticvoidmain(String[]args){//代码走到第 3 行的时候遇到了一个MathException这时第 4 行的代码就不会执行了代码直接跳转到catch语句中走到第 6 行的时候//异常机制有一个原则如果在catch中遇到了return或者异常等能使该函数终止的话那么有finally就必须先执行完finally代码块里面的代码然后再返回值。//因此代码又跳到第 8 行可惜第 8 行是一个return语句那么这个时候方法就结束了因此第 6 行的返回结果就无法被真正返回。//如果finally仅仅是处理了一个释放资源的操作那么该道题最终返回的结果就是2因此上面这道题返回值是3。System.out.println(getNum());}注只有在 try 里面通过 System.exit(0) 来退出 JVM 的情况下 finally 块中的代码才不会执行其他 return 等情况都会执行finally 代码块。5.8 java 中如何编写自定义异常自定义异常通常继承于Exception或RuntimeException到底继承那个应该看具体情况来定。自定义异常类可以有自己的变量和方法来传递错误代码或传递其它异常相关信息。实际工作中都会自定义异常类来处理异常。自定义受控异常/** * 自定义受控异常编译时、检查时异常checkedException继承Exception */classMyCheckedExceptionextendsException{publicMyCheckedException(){//调用父类的默认构造函数super();}publicMyCheckedException(Stringmessage){//手动调用父类的构造方法super(message);}}自定义非受控异常/** * 自定义非受控异常运行时异常-unCheckedException */classMyRuntimeExceptionextendsRuntimeException{publicMyRuntimeException(){//调用父类的默认构造函数super();}publicMyRuntimeException(Stringmessage){//手动调用父类的构造方法super(message);}}使用自定义异常/** * 使用自定义异常 */publicclassMyExceptionClass{publicstaticvoidmain(String[]args){testException1();testException2();}privatestaticvoidtestException1(){//【示例代码】自定义受控异常的使用try{method1(10,0);}catch(MyCheckedExceptione){//必须拦截,拦截后建议给出处理如果不给出处理就属于隐藏了该异常//系统将不给出任何提示使程序的调试非常困难System.out.println(e.getMessage());}}privatestaticvoidtestException2(){method2(10,0);}/** * 自定义受控异常的使用 * 如果是受控异常必须throws声明让调用方处理异常 * * param value1 * param value2 * throws MyCheckedException */privatestaticvoidmethod1(intvalue1,intvalue2)throwsMyCheckedException{if(value20){thrownewMyCheckedException(方法1自定义受控异常除数不能为0);}intvalue3value1/value2;System.out.println(value3);}/** * 【示例代码】自定义非受控异常的使用 * * param value1 * param value2 */privatestaticvoidmethod2(intvalue1,intvalue2){//throws MyRuntimeException {if(value20){//抛出非受控异常方法可以不使用throws进行声明但也可以显示的声明thrownewMyRuntimeException(方法2自定义非受控异常除数不能为0);}intvalue3value1/value2;System.out.println(value3);}}执行结果6 总结本文主要对Java中的异常相关的知识进行了一下总结。异常的分类受控异常和非受控异常的区别异常的捕获和抛出处理异常的捕获顺序先捕获小的再捕获大的方法覆盖和异常的关系异常的5个关键字try、catch、finally、throws、throw最后上一个异常的图来总结下Java中的异常如下图所示写博客是为了记住自己容易忘记的东西另外也是对自己工作的总结希望尽自己的努力做到更好大家一起努力进步如果有什么问题欢迎大家一起探讨代码如有问题欢迎各位大神指正给自己的梦想添加一双翅膀让它可以在天空中自由自在的飞翔