Listing 6
public SomeInterface buildInstance(String className)
throws ClassNotFoundException{
try{
Class clazz=Class.forName(className);
return(SomeInterface)clazz.newInstance();
}
catch(ClassNotFoundException e){
log.error("Invalid class name:"+className+","+e.toString());
throw e;
}
catch(InstantiationException e){
throw new ClassNotFoundException("Cannot create class:"+className,e);
}
catch(IllegalAccessException e){
throw new ClassNotFoundException("Cannot create class:"+className,e);
}
catch(ClassCastException e){
throw new ClassNotFoundException(className
+"does not implement"+SomeInterface.class.getName(),e);
}
}
在某些情况下,代码可恢复某些错误条件。在这种情况下,捕捉特殊异常很重要,这样代码才能计算出条件是否可以恢复。运用这种思想分析一下Listing 6中的类范例。
在Listing 7中,代码返回一个用于无效className的默认对象,但是给出了一个用于非法操作的异常,像无效数据类型转换或者安全违背。
注意:IllegalClassException是一个域异常类,这里提到它只是为了演示。
Listing 7
public SomeInterface buildInstance(String className)
throws IllegalClassException{
SomeInterface impl=null;
try{
Class clazz=Class.forName(className);
return(SomeInterface)clazz.newInstance();
}
catch(ClassNotFoundException e){
log.warn("Invalid class name:"+className+",using default");
}
catch(InstantiationException e){
log.warn("Invalid class name:"+className+",using default");
}
catch(IllegalAccessException e){
throw new IllegalClassException("Cannot create class:"+className,e);
}
catch(ClassCastException e){
throw new IllegalClassException(className
+"does not implement"+SomeInterface.class.getName(),e);
}
if(impl==null){
impl=new DefaultImplemantation();
}
return impl;
}
何时应该捕捉类属Exception
当捕捉类属Exception很方便而且有必要的时候就可以捕捉类属Exception。这些情况都是很特殊的,但是它对于大型的容错系统来说很重要。在Listing 8中,请求总是依次从请求队列中读取和处理。但是如果请求处理过程中出现任何异常的话(要么是BadRequestException要么是RuntimeException的任何一个子类,包括NullPointerException),那么循环时在处理之外可捕捉到该异常。所以任何错误都可使得处理循环停止,而且不能执行任何保存命令。这就表示请求处理过程中处理错误的方式不好:
Listing 8
public void processAllRequests(){
Request req=null;
try{
while(true){
req=getNextRequest();
if(req!=null){
processRequest(req);//throws BadRequestException
}
else{
//Request queue is empty,must be done
break;
}
}
}
catch(BadRequestException e){
log.error("Invalid request:"+req,e);
}
}
我们可以采用一个更好的方式来完成请求处理:对逻辑做两个完美的改变,如Listing 9。首先,将try/catch快移到请求处理循环内。这样,处理循环内的任何错误都可捕捉到并得到处理,而且它们也不会导致循环破裂。因此,循环继续处理请求,即使单个请求处理失败也没关系。其次,修改try/catch块,使他捕捉类属Exception,这样任何异常都可在循环内捕捉到而且请求也可以继续进行:
Listing 9
public void processAllRequests(){
while(true){
Request req=null;
try{
req=getNextRequest();
if(req!=null){
processRequest(req);//Throws BadRequestException
}
else{
//Request queue is empty,must be done
break;
}
}
catch(Exception e){
log.error("Error processing request:"+req,e);
}
}
}
捕捉类属Exception听起来好像违背了这部分开始时所说的原则——的确这样。但是具体情况具体分析。在此例中,捕捉类属Exception是为了防止单个异常造成整个系统停止。在请求、事务或者事件在循环内处理的情况下,循环需要继续进行,即使处理过程中出现异常也要进行。
在Listing 9中,处理循环中的try/catch块可看作最高级别异常处理器,这个最高级别异常处理器需要捕捉和记录出现在该级别的代码上的任何异常。这样,一场就不会被忽视和丢失,但是异常并不打断需要处理的请求的剩余部分。
捕捉和产生类属异常的处理方法(3)
作者:Paul Philion著陈姣姣翻译发文时间:2003.11.05
每一个大型的复杂的系统都有一个最高级别的异常处理器(也许每个子系统一个,取决于系统执行处理的方式)。最高级别的异常处理器无意解决产生异常的根本原因,但是它应该不必停止处理就能够捕捉和记录问题。这并不是说所有的异常都应该在这个级别给出。任何可在更低级别处理的异常,也就是说,当问题出现时哪里的逻辑了解更多的条件,就在哪里处理异常。但是如果异常在较低级别不能得到处理的话,继续前进并一路上给出异常。这样,所有那些不可恢复的错误只会在一个地方(最高级别的异常处理器)得到处理,而不是贯穿整个系统。
不给出类属Exception
Listing 1中给出的整个问题在程序员决定给出来自cleanupEverything()方法的类属Exception时就开始了。当方法给出六种不同的异常时代码变得相当混乱:方法的宣言变得不可读,调用方法被迫捕捉六种不同的异常,见Listing 10:
Listing 10
public void cleanupEverything()throws
ExceptionOne,ExceptionTwo,ExceptionThree,
ExceptionFour,ExceptionFive,ExceptionSix{
cleanupConnections();
cleanupFiles();
removeListeners();
}
public void done(){
try{
doStuff();
cleanupEverything();
doMoreStuff();
}
catch(ExceptionOne e1){
//Log e1
}
catch(ExceptionTwo e2){
//Log e2
}
catch(ExceptionThree e3){
//Log e3
}
catch(ExceptionFour e4){
//Log e4
}
catch(ExceptionFive e5){
//Log e5
}
catch(ExceptionSix e6){
//Log e6
}
}
但是即使代码有点凌乱,它至少还是清楚的。使用特殊的异常可避免几个非常现实的问题:给出类属Exception隐藏了根本问题的细节,从而没有机会来处理真正的问题。而且,给出类属Exception强迫到该方法的任何调用要么捕捉类属Exception(捕捉类属Exception有问题,如前面讨论的一样)要么通过重新给出类属Exception传播问题。
一般来说,当方法宣布它正给出类属Exception,它无非是下面两个原因中的一个:一种情况是方法调用了几种其他的可能给出许多不同异常的方法(像Mediator或者Fa?ade设计模式)并且隐藏了异常条件的细节。该方法不是创建和给出域级别的异常(用来包裹低级别的异常),它只是简单的宣布它要给出异常而且不管结果。另一种情况是方法例示并给出了类属Exception(throw new Exception())因为程序员根本就没有思考要使用何种异常才能真正的表达他所处的情况。
这两种情况都只要稍微思考设计一下就可以解决:详细的域级别的异常真正应该如何给出?这个设计包括简单的宣布方法要给出可能实际存在的异常。另一个方法是创建一个域级别的异常来包裹给出的异常并且宣布一下。在大多数情况下,方法给出的异常(或者异常组)应该尽可能的详细。详细的异常可提供有关错误条件的更多信息从而允许错误情况得到处理或者至少是得到详细记录。
类属Exception类为checked exception,意思是对宣布它给出Exception的方法的任何调用必须要么宣布它自己给出Exception,要么包裹方法调用在能够捕捉类属Exception的try/catch块内。我前面已经解释过与该方法有关的问题。
谨慎使用类属Exception
本文探讨了处理类属Exception的几个方面:它们不应该给出而且它们也不能被忽视,它们应该很少(只有在特殊情况下)被捕捉。它们不提供允许你有效处理它们的详细信息,也不提供允许你不再捕捉你不想捕捉的异常的详细信息。
异常是Java的一个强大的组成部分,只要使用正确,就能提高程序员的效率并缩短你的开发周期,特别是在测试和调试阶段。如果异常使用不正确,它们就会与你作对:隐藏你系统内的问题。注意你使用类属Exception的位置和方式。
public SomeInterface buildInstance(String className)
throws ClassNotFoundException{
try{
Class clazz=Class.forName(className);
return(SomeInterface)clazz.newInstance();
}
catch(ClassNotFoundException e){
log.error("Invalid class name:"+className+","+e.toString());
throw e;
}
catch(InstantiationException e){
throw new ClassNotFoundException("Cannot create class:"+className,e);
}
catch(IllegalAccessException e){
throw new ClassNotFoundException("Cannot create class:"+className,e);
}
catch(ClassCastException e){
throw new ClassNotFoundException(className
+"does not implement"+SomeInterface.class.getName(),e);
}
}
在某些情况下,代码可恢复某些错误条件。在这种情况下,捕捉特殊异常很重要,这样代码才能计算出条件是否可以恢复。运用这种思想分析一下Listing 6中的类范例。
在Listing 7中,代码返回一个用于无效className的默认对象,但是给出了一个用于非法操作的异常,像无效数据类型转换或者安全违背。
注意:IllegalClassException是一个域异常类,这里提到它只是为了演示。
Listing 7
public SomeInterface buildInstance(String className)
throws IllegalClassException{
SomeInterface impl=null;
try{
Class clazz=Class.forName(className);
return(SomeInterface)clazz.newInstance();
}
catch(ClassNotFoundException e){
log.warn("Invalid class name:"+className+",using default");
}
catch(InstantiationException e){
log.warn("Invalid class name:"+className+",using default");
}
catch(IllegalAccessException e){
throw new IllegalClassException("Cannot create class:"+className,e);
}
catch(ClassCastException e){
throw new IllegalClassException(className
+"does not implement"+SomeInterface.class.getName(),e);
}
if(impl==null){
impl=new DefaultImplemantation();
}
return impl;
}
何时应该捕捉类属Exception
当捕捉类属Exception很方便而且有必要的时候就可以捕捉类属Exception。这些情况都是很特殊的,但是它对于大型的容错系统来说很重要。在Listing 8中,请求总是依次从请求队列中读取和处理。但是如果请求处理过程中出现任何异常的话(要么是BadRequestException要么是RuntimeException的任何一个子类,包括NullPointerException),那么循环时在处理之外可捕捉到该异常。所以任何错误都可使得处理循环停止,而且不能执行任何保存命令。这就表示请求处理过程中处理错误的方式不好:
Listing 8
public void processAllRequests(){
Request req=null;
try{
while(true){
req=getNextRequest();
if(req!=null){
processRequest(req);//throws BadRequestException
}
else{
//Request queue is empty,must be done
break;
}
}
}
catch(BadRequestException e){
log.error("Invalid request:"+req,e);
}
}
我们可以采用一个更好的方式来完成请求处理:对逻辑做两个完美的改变,如Listing 9。首先,将try/catch快移到请求处理循环内。这样,处理循环内的任何错误都可捕捉到并得到处理,而且它们也不会导致循环破裂。因此,循环继续处理请求,即使单个请求处理失败也没关系。其次,修改try/catch块,使他捕捉类属Exception,这样任何异常都可在循环内捕捉到而且请求也可以继续进行:
Listing 9
public void processAllRequests(){
while(true){
Request req=null;
try{
req=getNextRequest();
if(req!=null){
processRequest(req);//Throws BadRequestException
}
else{
//Request queue is empty,must be done
break;
}
}
catch(Exception e){
log.error("Error processing request:"+req,e);
}
}
}
捕捉类属Exception听起来好像违背了这部分开始时所说的原则——的确这样。但是具体情况具体分析。在此例中,捕捉类属Exception是为了防止单个异常造成整个系统停止。在请求、事务或者事件在循环内处理的情况下,循环需要继续进行,即使处理过程中出现异常也要进行。
在Listing 9中,处理循环中的try/catch块可看作最高级别异常处理器,这个最高级别异常处理器需要捕捉和记录出现在该级别的代码上的任何异常。这样,一场就不会被忽视和丢失,但是异常并不打断需要处理的请求的剩余部分。
捕捉和产生类属异常的处理方法(3)
作者:Paul Philion著陈姣姣翻译发文时间:2003.11.05
每一个大型的复杂的系统都有一个最高级别的异常处理器(也许每个子系统一个,取决于系统执行处理的方式)。最高级别的异常处理器无意解决产生异常的根本原因,但是它应该不必停止处理就能够捕捉和记录问题。这并不是说所有的异常都应该在这个级别给出。任何可在更低级别处理的异常,也就是说,当问题出现时哪里的逻辑了解更多的条件,就在哪里处理异常。但是如果异常在较低级别不能得到处理的话,继续前进并一路上给出异常。这样,所有那些不可恢复的错误只会在一个地方(最高级别的异常处理器)得到处理,而不是贯穿整个系统。
不给出类属Exception
Listing 1中给出的整个问题在程序员决定给出来自cleanupEverything()方法的类属Exception时就开始了。当方法给出六种不同的异常时代码变得相当混乱:方法的宣言变得不可读,调用方法被迫捕捉六种不同的异常,见Listing 10:
Listing 10
public void cleanupEverything()throws
ExceptionOne,ExceptionTwo,ExceptionThree,
ExceptionFour,ExceptionFive,ExceptionSix{
cleanupConnections();
cleanupFiles();
removeListeners();
}
public void done(){
try{
doStuff();
cleanupEverything();
doMoreStuff();
}
catch(ExceptionOne e1){
//Log e1
}
catch(ExceptionTwo e2){
//Log e2
}
catch(ExceptionThree e3){
//Log e3
}
catch(ExceptionFour e4){
//Log e4
}
catch(ExceptionFive e5){
//Log e5
}
catch(ExceptionSix e6){
//Log e6
}
}
但是即使代码有点凌乱,它至少还是清楚的。使用特殊的异常可避免几个非常现实的问题:给出类属Exception隐藏了根本问题的细节,从而没有机会来处理真正的问题。而且,给出类属Exception强迫到该方法的任何调用要么捕捉类属Exception(捕捉类属Exception有问题,如前面讨论的一样)要么通过重新给出类属Exception传播问题。
一般来说,当方法宣布它正给出类属Exception,它无非是下面两个原因中的一个:一种情况是方法调用了几种其他的可能给出许多不同异常的方法(像Mediator或者Fa?ade设计模式)并且隐藏了异常条件的细节。该方法不是创建和给出域级别的异常(用来包裹低级别的异常),它只是简单的宣布它要给出异常而且不管结果。另一种情况是方法例示并给出了类属Exception(throw new Exception())因为程序员根本就没有思考要使用何种异常才能真正的表达他所处的情况。
这两种情况都只要稍微思考设计一下就可以解决:详细的域级别的异常真正应该如何给出?这个设计包括简单的宣布方法要给出可能实际存在的异常。另一个方法是创建一个域级别的异常来包裹给出的异常并且宣布一下。在大多数情况下,方法给出的异常(或者异常组)应该尽可能的详细。详细的异常可提供有关错误条件的更多信息从而允许错误情况得到处理或者至少是得到详细记录。
类属Exception类为checked exception,意思是对宣布它给出Exception的方法的任何调用必须要么宣布它自己给出Exception,要么包裹方法调用在能够捕捉类属Exception的try/catch块内。我前面已经解释过与该方法有关的问题。
谨慎使用类属Exception
本文探讨了处理类属Exception的几个方面:它们不应该给出而且它们也不能被忽视,它们应该很少(只有在特殊情况下)被捕捉。它们不提供允许你有效处理它们的详细信息,也不提供允许你不再捕捉你不想捕捉的异常的详细信息。
异常是Java的一个强大的组成部分,只要使用正确,就能提高程序员的效率并缩短你的开发周期,特别是在测试和调试阶段。如果异常使用不正确,它们就会与你作对:隐藏你系统内的问题。注意你使用类属Exception的位置和方式。
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货