Java中的异常处理

JAVA异常处理

异常:

是什么?是对问题的描述,见问题进行对象的封装

 

异常机制可以使程序中的异常处理代码和正常业务分离,保证程序代码更加优雅,并可以提高程序的健壮性。

1.异常基本概念

程序在运行时发生错误是不可避免的

在进行错误处理时,发现错误根据具体的情况可以划分为两大类

1.致命错误

不可恢复,例如内存泄露

2.非致命错误

读取一个文件,文件不存在

修改一个文件夹的名字,但是文件夹目前被使用

2.异常处理的思想

1.对于无法处理的错误,基于面向对象的思想,Java语言对其进行封装,成为一个对象,名字叫做Error,即不可恢复的错误

2.对于某些非致命性的错误,可以通过某种形式进行处理,Java语言对其进行封装,称为一个对象,名字叫做Exception,即可处理的异常现象

3.异常体系

异常体系:

    Throwable

        Error

        Exception

            RuntimeException

异常体系的特点:1.异常体系中的所有类以及建立的对象都具备可抛性

                2.也就是说可以被throws和throw关键字所操作

                3.只有异常体系具备这个特点

 

Java的异常被分为两类:Checked ( 编译时异常 ) 异常和    Runtime异常(运行时异常),所有的RuntimeException类及其子类的实例被称为Runtime异常;不是RuntimeException类及其子类的异常实例则被称为Checked异常。

 

Checked异常体现了java的设计哲学———没有完善错误处理的代码根本就不会被执行

对于Checked异常的处理方式有两种:

1.当前方法明确知道如何处理该异常,程序应该使用try...catch块来捕获该异常,然后在对应的catch块中修复该异常。

2.当前方法不知道如何处理该这种异常,应该在定义方法声明时抛出该异常。

 

Runtime异常则更加灵活,Runtime异常无需显式声明抛出,如果程序需要捕获Runtime异常,也可以用try...catch块来实现。

4.异常的分类

1.异常体系的分类非常庞大

2.常见的异常

NullPointException

IOException

SQLException

 

如果函数声明了异常,调用者需要进行处理,处理方式:

可以throws    可try。

 

1,编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。

              这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。

              这样的问题都可以针对性的处理。

 

2,编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。

这种问题的发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的而或者引发              了内部状态的改变导致的。

那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者             对代码进行修正。

5.异常处理器

try…catch…finally(TCF结构)

       语法结构:

       try{

              可能引发异常的语句//业务实现代码

       }catch(可能出现的异常现象){

              针对异常现象的处理语句

       }finally{

               (清理现场)

       }

如果执行try块里的业务逻辑代码时出现异常,系统会自动生成一个异常对象,该异常对象被提交给Java运行环境,这个过程被称为———抛出(throws)异常。

 

当java运行环境收到异常对象时,会寻找处理该异常对象的cathch块,如果找到合适的catch块,则把该异常对象交给该catch处理,这个过程被称为———捕获(catch)异常;如果java运行环境找不到捕获异常的代码块,则运行时环境终止,java程序也将退出。

                                                                                         

 注意:进行异常捕获时,一定要记住要先捕获小异常,再捕获大异常。

try块与if语句不一样,try块后的花括号({....})不可以省略,即使try块里只有一行代码,也不能省略这个花括号,与之类似的是,catch后的花括号也不能省略,还有一点需要指出try块里声明的变量时代码块内局部变量,它只在try块内有效,在catch块内不能访问。

6.异常处理器——try

try语句块用于包裹可能引发异常的语句

try语句块中的语句不是一定会引发异常现象的

try语句块中的语句一旦引发异常,程序执行流程将自动跳转到对应的处理代码中,则从引发异常的语句向后直到try语句块结束大括号处的代码将不再运行

7.异常处理器——catch

catch语句块定义了针对try语句块中所引发的异常进行分门别类的处理

一个try语句块可以携带一个或多个catch语句块,但是只能引发其中任意一个处理方案,不可能执行一种以上的处理方法

catch语句块超过一个时,需要对其层次进行自上而下由小到大的层级排列,相互之间没有层级关系的语句可以随意排列顺序,不做要求

catch是用于处理异常,如果没有catch就代表异常没有被

处理过,如果该异常是检测时异常,那么就必须声明。

 

8.异常处理器——finally

fianlly代码块:定义一定执行的代码,通常用于关闭资源

finally语句块定义了一段总是被运行的代码,无论try语句块中是否出现异常现象

finally语句块通常用于做现场清理的工作,例如try语句块中打开了一个文件,但是由于运行过程中出现了异常,转入到catch执行处理代码后,文件并没有被正常关闭,此时需要利用finally语句块来进行处理,将文件正常关闭

Java的垃圾回收机制不会回收任何物理资源,垃圾回收机制只能回收对内存中对象所占用的内存。

 

不要在finally块中使用如returnthrow等导致方法终止的语句,一旦在finally块中使用了returnthrow语句,将会导致try块,catch块中的returnthrow语句失效。

 

 1.finally中定义的通常是关闭资源代码,因为资源必须释放。

    2.finally只有一种情况不会执行,当执行到System.exit(0):系统推出,finally不会执行。

9.异常处理器——catch与finally

异常处理器中的catch与finally可以共存,一个try语句可以携带一到多个catch语句块,但是只能携带一个finally语句块

异常处理器可以选择只携带catch语句块或finally语句块

 

异常处理流程代码也可以放在任何可能放可执行性代码的地方,因此完整的异常处理流程既可以放在try块里,也可以放在catch块,finally块里。

10.异常信息处理

catch语句块中针对出现的异常现象根据Java面向对象的原则,将出现的问题包装成一个对象,该对象中包含了异常现象对应的所有信息

异常对象名称

引发异常的原因

异常出现的位置(错误堆栈)

11.异常信息获取

catch语句块中针对出现的异常现象根据Java面向对象的原则,将出现的问题包装成一个对象,该对象中包含了异常现象对应的所有信息

1.异常对象名称

toString()

2.引发异常的原因

getMessage()

3.异常出现的位置(错误堆栈)

printStackTrace()

4.返回该异常的跟踪栈信息

getStackTrsce()

12.自定义异常

自定义异常即扩展Exception类,创建异常类对象

 

用户自定义异常都应该继承Exception基类,如果希望自定义Runtime异常,则应该继承RuntimeException基类。定义异常时通常需要提供两个构造器:一个是无参数的构造器;另一个是带一个字符串参数的构造器,这个字符串将作为该异常对象的描述信息(也就是异常对象的getMessage()方法的返回值)。

 下面穿件了一个自定义异常类:

public class AuctionException extends Exception

{

       //无参数的构造器

       public AuctionException(){}      

       //带一个字符串参数的构造器

       public AuctionException(String msg)   

       {

              super(msg);

       }

}

 

13.异常对象抛出

自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装。

 

1.针对某种异常现象可以指定抛出何种异常,在抛出异常时,使用throw指令抛出具体的异常对象

throw 异常对象

2.抛出异常对象后,JVM将检测抛出的异常是否被处理,此时可以通过下列两种形式来进行处理

对抛出的异常进行捕获

对抛出的异常不进行捕获,继续向上层调用者抛出

 

13.1使用throws声明抛出异常

使用throws声明抛出异常的思路是:当前方法不知道如何处理这种类型的异常,该异常该有上一级调用者处理;如果main方法也不知道该如何处理这种类型的异常,也可以使用throws抛出异常,该异常将交给JVM处理。JVM对异常的处理方法是:打印异常的跟踪栈信息,并终止程序运行,这就是前面程序在遇到异常后自动结束的原因。

 

Throws声明抛出只能在方法签名中使用,throws可以声明抛出多个异常类,多个异常类之间可以逗号隔开。Throws声明抛出的语法格式如下:

 throws  ExceptionClass1,ExceptionClass2...

一旦使用了throws声明抛出该异常,程序就无须使用try...catch块来捕捉异常了。也就是说,调用该方法时,要么放在try块中显式捕获该异常,要么放在另一个带throws声明抛出的方法中,

 

public class ThrowsTest 

{

       public static void main(String[] args) throws Exception

       {

              //因为test()方法声明抛出IOException异常

              //所以调用该方法的代码块要么处于try...catch中,

              //要么处于另一个带throws声明抛出异常的方法中

             test();          

       }

       public static void test()throws IOException

       {

              //因为FileInputStresm的构造器声明抛出IOException异常

              //所以调用FileInputStream的代码要么处于try...catch块中

              //要么处于另一个带throws声明抛出的方法中

              FileInputStream fis = new FileInputStream("a.txt");

       }

}

 

Check异常的优势:——Check异常能在编译时提醒程序员代码可能存在的问题,提醒程序员必须处理该异常,或者声明该异常由该方法调用者来处理,从而可以避免程序员因为粗心而忘记处理该异常的错误。

13.2使用throw抛出异常

当程序出现错误时,系统会自行抛出异常;除此之外,Java也允许程序自行抛出异常,自行抛出异常使用throw语句来完成。

 

如果需要在程序中自行抛出异常,则应使用throws语句,throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例,语法格式如下:

throw ExceptionInstance

 

 如果throw语句抛出的异常是Checked异常,则该throw语句要么处于try块里,显式捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给该方法的调用者来处理;

 如果throw抛出的是Runtime异常,则该语句无须放在try块里,也无须放在带throws声明抛出的方法中,程序既可以显式使用try..catch来捕获并处理该异常,也可以完全不理会该异常,把该异常交给该方法调用者来处理。

 

13.3throws和throw的用法

throw定义在函数内,用于抛出异常对象

throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开

 

当函数内有throw抛出异常对象,并未进行try处理,必须在函数上声明,

否则都将编译失败。

注意:RuntimeException除外,也就是说,函数内如果抛出的是RuntimeException

异常,函数上可以不用声明。

 

14.方法抛出异常

1.方法抛出异常是对方法的定义进行声明,明确方法执行过程中可能引发异常现象,提醒调用者要对其进行处理

2.方法抛出异常要求调用者强制处理,除非抛出的异常为RuntimeException的子类,否则必须对其进行处理。可以利用此特点,设计自定义异常类的对象

15.异常处理的应用

1.异常现象在编程过程中及其常见,在开发过程中,如果调用了可能引发异常的语句,最常见的处理方案是针对对应的语句使用tcf结构对其进行处理,并打印错误的异常堆栈信息,然后针对错误信息进行分析,制作对应的异常处理方案

2.在开发调试期间,打印的异常信息可以作为编程人员的参考性信息,但是在实际运行期间,此类信息必须要屏蔽掉,以更友好的形式展示给最终用户

16.异常在子父类覆盖中的体现

1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。

2.如果父类方法抛出多个异常,子类在覆盖该方法时,子类只能抛出父类异常的子集

3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常,如果子类方法发生了异常,就必须进行try处理,绝对不能抛。

*/

Exception

    |--AException

        |--BException

    |--CExcepton

*/

//定义了3个异常类

class AException extends Exception{

}

class BException extends AException{   

}

class CException extends AException{

}

//父类抛出A异常

class Fu{

    void show() throws AException{ 

    }

}

class Test{

    void function(){   

        try{

            f.show();

        }catch (AException e){

        }

    }

}

//子类只能抛出A异常或者B异常

class Zi extends Fu{

    void show() throws BException{ 

    }

}

 

17.异常的处理原则

    1.处理方式有两种:try或者 throws

    2.调用到抛出异常的功能时,抛出几个,就处理几个

        一个try对应对个catch

    3.多个catch,父类的catch放到最下面

    4.catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,

      输出语句,也不要不写。

      当捕获到的异常,本功能处理不了时,可以继续再catch中抛出,

      try{

        throw new AExcepton();

      }catch(AException e){

        throw e;

      }

        如果该异常处理不了时,但并不属于该功能出现的异常,

        可以将异常转换周,在抛出和该功能相关的异常。

 

        或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,

        让调用者知道,并处理。也可以将捕获异常处理后,转换新的异常。

 

        try{

            throw new BException();

        }catch(AException e){

            //对AException处理

            throw new BException();

        }

 

异常的注意事项:

    在子父类覆盖时;

    1.子类抛出的异常必须是父类异常的子类或者子集

    2.如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛

 

18.异常相关面试

针对finally语句块的执行特点,如果在finally语句块中添加了return语句,则执行到此处时,会对整体方法的返回值进行修改。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值