Java中的异常处理

来源:互联网 发布:c语言access violation 编辑:程序博客网 时间:2024/05/18 01:03

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

{

      //无参数的构造器

      publicAuctionException(){}      

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

      public AuctionException(Stringmsg)   

      {

             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 extendsAException{   

}

class CException extends AException{

}

//父类抛出A异常

class Fu{

    voidshow() throws AException{ 

    }

}

class Test{

    voidfunction(){   

       try{

           f.show();

       }catch (AException e){

       }

    }

}

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

class Zi extends Fu{

    voidshow() 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
原创粉丝点击