快精灵印艺坊 您身边的文印专家
广州名片 深圳名片 会员卡 贵宾卡 印刷 设计教程
产品展示 在线订购 会员中心 产品模板 设计指南 在线编辑
 首页 名片设计   CorelDRAW   Illustrator   AuotoCAD   Painter   其他软件   Photoshop   Fireworks   Flash  

 » 彩色名片
 » PVC卡
 » 彩色磁性卡
 » 彩页/画册
 » 个性印务
 » 彩色不干胶
 » 明信片
   » 明信片
   » 彩色书签
   » 门挂
 » 其他产品与服务
   » 创业锦囊
   » 办公用品
     » 信封、信纸
     » 便签纸、斜面纸砖
     » 无碳复印纸
   » 海报
   » 大篇幅印刷
     » KT板
     » 海报
     » 横幅

Java中非常机制的深入研究

由于本文旨在探讨Java"非常机制"的深层原理,因此关于"非常"的使用方式都不做具体说明。首先看一段异常认识的用于打开一个文件的C程序段:

FILE *fp;
fp=fopen(filename,"rw");
if(fp==NULL){
printf("cannot open file/n");
exit(0);
}



在这段程序中,if条件语句中的一段用来处理没有找到指定文件,或者其它原因无法准确打开指定文件。可是假如碰到一个责任心不强的程序员,他可能认为出现找不到文件的可能性很小,或者由于思路集中在程序功能的实现上而忘记了处理这种情况。这时程序同样可以准确编译,而且一般情况下也不会出现问题。但此时这段程序可以肯定说是不够健壮的,而且一旦这段程序发生了错误也会让程序员很难发现错误出在哪里。在C语言以及其它大多数高级语言中都可以举出很多这种例子。

也就是一个函数在使用的时候,可能会出现并没有达到这个函数的使用目的的情况,哪怕在这段程序的特定使用环境下发生这种非常情况的可能性只有万分之一。常用处理的方式就是,程序员在需要使用某个函数时必须充分了解可能会有什么原因导致该函数不能准确执行,然后加入相应的条件判定语句来进行处理。后面将有一个例子说明这个问题。

而Java的"非常机制"就是在处理上述问题中给了程序员异常简朴而灵活的方法。一般来说,其它高级语言主要是让函数使用者来关注该函数可能会出现的非常情况,而java则是把这件事情交给方式(和函数对应的概念,在Java中称方式)的设计者来做。这对于方式的使用者来说带来的方便是不会因为责任心不强,或者办事丢三那四,会忘了在使用方式时处理可能发生的非常情况。而麻烦就是,在使用一个可能会发生非常的方式时,绝对不能视而不见,而必须做出相应的处理。也就是说象上述C程序段中,假如忘了if程序块,这个程序甚至还能蒙过一个外行上司,但当使用Java来完成这个功能时,只要用到的方式使用了"非常"机制,假如不对可能产生"非常"的方式进行相应处理,java编译器是不会让其通过的。

一、"非常类"的组织形式

Java系统类中的方式产生的非常都被组织成"非常类"(还有Error类,不在本文讨论范围),此方式和它相关的"非常类"通过throws要害字关联在一起,并且这些类都必须是Exception类的子类。任何一个自己开发的类的方式中假如可能会产生某种非常,也可以将这种非常组织成一个"非常类",但这个"非常类"同样必须是Exception的子类,或孙子类等等。

例1:

/*isLegal于检查数据是否合法,当>0时视为合法,返回合法值,
*否则视为不合法,抛出"非常"。*/
int isLegal(int dt) throws LowZeroException//这种定义本文中均称为方式与"非常"通
{                  //过throws建立了关联
if(dt>=0){
return data;
}
else
throw new LowZeroException();
}
/*自已写的非常类,继续自Exception*/
class LowZeroException extends Exception
{
public LowZeroException(){
super();
}
}



仔细观察方式isLegal(),它体现出的最值得注重的特色是,它有两种方法的函数出口,一种是通过return语句,返回的是方式本身定义的类型的实例,另一种是通过throw,返回的是"非常类"的对象实例,Java中称之为抛出"非常"。对比一下C中如何处理同样的问题的:

int isLegal(int dt) {
if(dt>=0){
return data;
}
else
return -1;//通过一个特定值来表明出错
}



由于C只能通过return返回函数值,所以在处理非常情况时则可能通过以上方法来处理。当然这就要求isLegal()函数的使用者必须知道函数中使用返回值-1来表明出现不合法数据的情况。

对比这两种处理方式,可以知道java的"非常机制"把处理非常事件的职能和方式本身的职能通过两个不同出口分离开来。

所有这些"非常类"独立于它详细服务的方式被统一组织成一个类树。"非常机制"就好比高校的后勤社会化相同,通过后勤社会化将学校的教学职能和学校的后勤保障分离开来,并且后勤集团的组织形式也是独立于学校主体的。事实证实,这种组织方法不仅提高了服务效率,也提高了服务质量。整个Java体系中的"非常类"组织形式如图1所示:







在例1中的isLegal()方式假如在调用过程中没有能正常返回整形数,而是在"非常"产生点产生了"非常"对象,那么这个"非常"对象由谁来接收,并处理它呢?以下就来解答这个问题。

二、"非常"的处理过程

Java中由try…catch语法来处理"非常",将关联有"非常类"的方式包含在try{}程序块中,catch(){}要害字可以使用形参,用于和方式产生的"非常"对象结合。当调用某个方式时,引起非常事件发生的条件成立,便会抛出"非常",原来的程序流程将会在此方式处中断,然后try模块后紧跟的catch中的"形参"和此非常对象完成了结合,继而进入了catch模块中运行。详细过程举例说明:

例2:

/*将关联有非常的方式包含在try模块中*/
int myMethod(int dt){
int data = 0;
try{
int data = isLegal(dt);
}catch(LowZeroException e){
System.out.println("发生数据错误!");
}
return data;
}



三、"非常"的处理方式

有两种方式处理"非常":第一种如例2,将含有"非常"出口的方式直接放到try块中,然后由紧随其后的catch块捕获。第二种是不直接监听捕获被引用方式的"非常",而是将这个"非常"关联传递给引用方式,同时监听捕获工作也相应向上传递。

例3:

int myMethod2(int dt)
{
int data = 0;
try{
data = myMethod(dt)
}catch(LowZeroException e){
System.out.println("发生数据错误!");
e.printStackTrace();
}
return data;
}

int myMethod(int dt) throws LowZeroException
{
int data = isLegal(dt); //此处引用isLegal()方式,但并没有捕获它的"非常"
return data;
}



从上例中可以看到方式myMethod()与它引用的方式isLegal()产生的"非常"LowZeroException建立了关联,也就是完成了将"非常"关联的向上传递,此时的myMethod()方式体中虽然只有一个return返回语句,但它事实上同样有两种方法的函数出口,一种是由return返回的整形值,另一种则是返回方式名中的throws要害字所指的"非常类"的实例对象。相应的,监听捕获的工作交给了上一层方式myMethod2()。同样的道理,myMethod2()也可以将"非常"通过throws的关联继承向上传递。这样的话,一旦一个"非常"被捕获到时,这个"非常"必有一个传递路径,而假如我们在捕获点的catch程序块中加入printStackTrace()方式,便能清晰的看到这个"非常"是怎样传递过来的。例如在例3假如有"非常"被捕获到,e.printStackTrace()打印出来的结果将是:

LowZeroException:

at Example.isLegal

at Example myMethod

at Example.myMethod2

at Example main

从上结果中我们可以看到,从LowZeroException"非常"产生点,即包含throw new LowZeroException();子句的方式开始,然后一直追溯到产生当前线程的方式(注重:printStackTrace()并不是追溯到捕获点结束,而是到产生当前线程的方式结束)。"非常"产生点产生的LowZeroException"非常"对象,首先被赋给了isLegal()关联的LowZeroException类的无名引用,然后继承赋给myMethod()关联的LowZeroException类的无名引用,再继承赋给myMethod2()中的catch块中的形参e,最后在这里被处理掉,这个"非常"对象随即消失。可以说,catch(){}就是"非常"对象的生命终结点。

另外还要注重一点,方式与"非常"的关联可以一直向上传递,当传递到与main方式关联后,即在main()方式的定义中使用了throws Exception,这时除了虚拟机没有其它方式能够引用main()方式,且在程序中可能看不到try…catch程序块,但并不会产生错误,因为此时虚拟机会捕获"非常",并且会默认的调用printStackTrace()方式打印出"非常"路径。总之只要一个方式关联了"非常",可以将这个"非常"关联向上传递,但是最终必须使用catch来终止"非常",或者一直传递到main()方式交给Java虚拟机来结束"非常"对象的生命,否则是通不过编译的。

四、使用"非常机制"的需要注重的几点

1.一个方式中可能会产生多种不同的非常,你可以设置多个"非常"抛出点来解决这个问题。

2."非常"对象从产生点产生后,到被捕获后终止生命的全过程中,实际上是一个传值过程,所以你可以根据需要,来合理的控制检测到"非常"的粒度。例如在例3中,假如你并不需要知道详细产生的是LowZeroException"非常",那么你可以使用"非常"的公共父类Exception来结合"非常"对象,即catch(Exception e){…}。同样在"非常"与方式关联的传递过程中,也可以根据需要控制关联"非常"的粒度,即throws后面跟上非常对象的父类名。

3."非常机制"中还有一种特别情况?D?DRuntimeException"非常类"(见图1),这个"非常类"和它的所有子类都有一个特性,就是"非常"对象一产生就被Java虚拟机直接处理掉,即在方式中出现throw 子句的地方便被虚拟机捕获了。因此凡是抛出这种"运行时非常"的方式在被引用时,不需要有try…catch语句来处理"非常"。




返回类别: 教程
上一教程: Resin2.1.12的数据库连接池配置
下一教程: JB的调试方式(欢迎补充)

您可以阅读与"Java中非常机制的深入研究"相关的教程:
· Java中非常机制的研究
· JAVA虚拟机的深入研究
· 关于java非常处理机制的深入理解
· 设计模式之Factory深入研究
· Structs深入研究(一)-----Struts framework的工作原理和组件
    微笑服务 优质保证 索取样品