处理Exception的几种实践,很

北京治疗白癜风的权威医院 http://yyk.39.net/bj/zhuanke/89ac7.html
在Java中处理异常并不是一个简单的事情。不仅仅初学者很难理解,即使一些有经验的开发者也需要花费很多时间来思考如何处理异常,包括需要处理哪些异常,怎样处理等等。

这也是绝大多数开发团队都会制定一些规则来规范对异常的处理的原因。而团队之间的这些规范往往是截然不同的。

本文给出几个被很多团队使用的异常处理 实践。

在Finally块中清理资源或者使用try-with-resource语句

当使用类似InputStream这种需要使用后关闭的资源时,一个常见的错误就是在try块的 关闭资源。

publicvoiddoNotCloseResourceInTry(){FileInputStreaminputStream=null;try{Filefile=newFile("./tmp.txt");inputStream=newFileInputStream(file);//usetheinputStreamtoreadafile//doNOTdothisinputStream.close();}catch(FileNotFoundExceptione){log.error(e);}catch(IOExceptione){log.error(e);}}

上述代码在没有任何exception的时候运行是没有问题的。但是当try块中的语句抛出异常或者自己实现的代码抛出异常,那么就不会执行 的关闭语句,从而资源也无法释放。

合理的做法则是将所有清理的代码都放到finally块中或者使用try-with-resource语句。

publicvoidcloseResourceInFinally(){FileInputStreaminputStream=null;try{Filefile=newFile("./tmp.txt");inputStream=newFileInputStream(file);//usetheinputStreamtoreadafile}catch(FileNotFoundExceptione){log.error(e);}finally{if(inputStream!=null){try{inputStream.close();}catch(IOExceptione){log.error(e);}}}}publicvoidautomaticallyCloseResource(){Filefile=newFile("./tmp.txt");try(FileInputStreaminputStream=newFileInputStream(file);){//usetheinputStreamtoreadafile}catch(FileNotFoundExceptione){log.error(e);}catch(IOExceptione){log.error(e);}}

指定具体的异常

尽可能的使用 体的异常来声明方法,这样才能使得代码更容易理解。

publicvoiddoNotDoThis()throwsException{...}publicvoiddoThis()throwsNumberFormatException{...}

如上,NumberFormatException字面上即可以看出是数字格式化错误。

对异常进行文档说明

当在方法上声明抛出异常时,也需要进行文档说明。和前面的一点一样,都是为了给调用者提供尽可能多的信息,从而可以更好地避免/处理异常。异常处理的10个 实践,这篇也推荐看下。

在Javadoc中加入throws声明,并且描述抛出异常的场景。

/***Thismethoddoessomethingextremelyuseful...**

paraminput*

throwsMyBusinessExceptionif...happens*/publicvoiddoSomething(Stringinput)throwsMyBusinessException{...}

抛出异常的时候包含描述信息

在抛出异常时,需要尽可能精确地描述问题和相关信息,这样无论是打印到日志中还是监控工具中,都能够更容易被人阅读,从而可以更好地定位具体错误信息、错误的严重程度等。

但这里并不是说要对错误信息长篇大论,因为本来Exception的类名就能够反映错误的原因,因此只需要用一到两句话描述即可。

try{newLong("xyz");}catch(NumberFormatExceptione){log.error(e);}

NumberFormatException即告诉了这个异常是格式化错误,异常的额外信息只需要提供这个错误字符串即可。当异常的名称不够明显的时候,则需要提供尽可能具体的错误信息。

首先捕获 体的异常

现在很多IDE都能智能提示这个 实践,当你试图首先捕获最笼统的异常时,会提示不能达到的代码。当有多个catch块中,按照捕获顺序只有 个匹配到的catch块才能执行。因此,如果先捕获IllegalArgumentException,那么则无法运行到对NumberFormatException的捕获。

publicvoidcatchMostSpecificExceptionFirst(){try{doSomething("Amessage");}catch(NumberFormatExceptione){log.error(e);}catch(IllegalArgumentExceptione){log.error(e)}}

#不要捕获Throwable

Throwable是所有异常和错误的父类。你可以在catch语句中捕获,但是永远不要这么做。如果catch了throwable,那么不仅仅会捕获所有exception,还会捕获error。而error是表明无法恢复的jvm错误。因此除非 肯定能够处理或者被要求处理error,不要捕获throwable。

publicvoiddoNotCatchThrowable(){try{//dosomething}catch(Throwablet){//dontdothis!}}

不要忽略异常

很多时候,开发者很有自信不会抛出异常,因此写了一个catch块,但是没有做任何处理或者记录日志。

publicvoiddoNotIgnoreExceptions(){try{//dosomething}catch(NumberFormatExceptione){//thiswillneverhappen}}

但现实是经常会出现无法预料的异常或者无法确定这里的代码未来是不是会改动(删除了阻止异常抛出的代码),而此时由于异常被捕获,使得无法拿到足够的错误信息来定位问题。合理的做法是至少要记录异常的信息。

publicvoidlogAnException(){try{//dosomething}catch(NumberFormatExceptione){log.error("Thisshouldneverhappen:"+e);}}

不要记录并抛出异常

可以发现很多代码甚至类库中都会有捕获异常、记录日志并再次抛出的逻辑。如下:

try{newLong("xyz");}catch(NumberFormatExceptione){log.error(e);throwe;}

这个处理逻辑看着是合理的。但这经常会给同一个异常输出多条日志。如下:

17:44:28,ERRORTestExceptionHandling:65-java.lang.NumberFormatException:Forinputstring:"xyz"Exceptioninthread"main"java.lang.NumberFormatException:Forinputstring:"xyz"atjava.lang.NumberFormatException.forInputString(NumberFormatException.java:65)atjava.lang.Long.parseLong(Long.java:)atjava.lang.Long.(Long.java:)at


转载请注明:http://www.xxcyfilter.com/zyjn/zyjn/11987.html