前言Java异常处理的十个建议,希望对大家有所帮助~本文已上传至github:https://github.com/whx123/JavaHome1.尽量不要使用e.printStackTrace(),而不是使用日志打印。反例:try{//dowhatyouwant}catch(Exceptione){e.printStackTrace();}正例:try{//dowhatyouwant}catch(Exceptione){log.info("你的程序有异常,{}",e);}原因:printStackTrace()打印的堆栈日志与业务代码日志交错,不方便查看异常日志。e.printStackTrace()语句生成的字符串记录堆栈信息。如果信息太长,字符串常量池所在的内存块没有空间,也就是内存满了,那么用户的请求就会卡住~2.异常被捕获,但是具体的异常没有打印出来,因此无法更好地定位问题。反例:try{//dowhatyouwant}catch(Exceptione){log.info("你的程序有异常");}正例:try{//dowhatyouwant}catch(Exceptione){log.info("你的程序有异常")anexception,{}",e);}原因:在反例中,异常没有释放,到时候会很难排查问题好吧,是SQl错误还是IO异常,还是什么的别的?所以应该把异常打印到日志中~第三,不要用一个Exception来捕获所有可能的异常:publicvoidtest(){try{//...抛出IOException的代码调用//...抛出的代码调用SQLException}catch(Exceptione){//用基类Exception捕获所有可能的异常。如果这样捕获了多个级别,就会丢失原来异常的有效信息。log.info("Exceptionintest,exception:{}",e);}}正例:publicvoidtest(){try{//...抛出IOException的代码调用//...抛出SQLException的代码调用}catch(IOExceptione){//只捕获IOExceptionlog.info("IOExceptionintest,exception:{}",e);}catch(SQLExceptione){//只捕获SQLExceptionlog.info("SQLExceptionintest,exception:{}",e);}}原因:使用基类Exception来捕获所有可能的异常。如果这样捕获多层,原始异常的有效信息就会丢失。四、记得用finally关闭流资源或者直接用try-with-资源反例:FileInputStreamfdIn=null;try{fdIn=newFileInputStream(newFile("/jay.txt"));//关闭这里的流资源?有什么问题吗?如果发生异常怎么办?fdIn.close();}catch(FileNotFoundExceptione){log.error(e);}catch(IOExceptione){log.error(e);}正例1:需要使用finally关闭流资源,如下FileInputStreamfdIn=null;试试try{if(fdIn!=null){fdIn.close();}}catch(IOExceptione){log.error(e);}}正例2:当然也可以使用新特性try-with-JDK7的resource来处理,它是Java7提供的一个新特性,用于自动资源管理。资源是程序用完后必须关闭的对象。try-with-resources保证每个声明的资源都将在语句结束时关闭。什么样的对象可以作为资源?只要对象实现了java.lang.AutoCloseable接口或者java.io.Closeable接口,就OK了。try(FileInputStreaminputStream=newFileInputStream(newFile("jay.txt")){//useresources}catch(FileNotFoundExceptione){log.error(e);}catch(IOExceptione){log.error(e);}原因:如果不是使用finally或者try-with-resource,当程序出现异常,IO资源流没有关闭的时候,那么IO资源就会一直被它占用,让别人无法使用,造成了资源的浪费资源。5.捕获的异常和抛出的异常必须完全匹配,或者捕获的异常是抛出异常的父类反例://BizExceptionisasubclassofExceptionpublicclassBizExceptionextendsException{}//抛出父类Exceptionpublicstaticvoidtest()throwsException{}try{test();//编译错误}catch(BizExceptione){//捕获异常子类不能匹配log.error(e);}正例://throwsubclassExceptionpublicstaticvoidtest()throwsBizException{}try{test();}catch(Exceptione){log.error(e);}第六,捕获到的异常不能忽略,至少记录一下。反例:publicstaticvoidtestIgnoreException()throwsException{try{//dosomething}catch(Exceptione){//一般不会出现这种异常}}正例:publicstaticvoidtestIgnoreException(){try{//Dothings}catch(Exceptione){//一般不会有这个异常log.error("这个异常不应该在这里出现,{}",e);}}原因:虽然是正常情况下不会出现的异常,但是如果你catch了,不要不理它,至少打个log吧~7.注意异常对你Infectionofcodehierarchy的影响(早发现早治疗)反例:publicUserInfoqueryUserInfoByUserId(Longuserid)throwSQLException{//根据查询数据库theuserId}正例:publicUserInfoqueryUserInfoByUserId(Longuserid){try{//根据userId查询数据库}catch(SQLExceptione){log.error("查询数据库异常,{}",e);}finally{//关闭连接,清理资源}}原因:我们的项目一般将代码分为Action、Service、Dao等不同层次结构,如果你是DAO层处理的异常,尽快处理,如果向上抛SQLException,上层代码还是要用trycatch来处理,污染你的代码~八、自定义封装异常,不要丢弃原来异常的信息Throwablecause我们经常想捕获一个异常再抛出一个异常,以及想保留原来异常的信息,称为异常链公司框架提供统一的异常处理,使用异常链。我们自定义封装异常,不要丢弃原来的异常信息,否则排错会很头疼。反例:publicclassTestChainException{publicvoidreadFile()throwsMyException{try{InputStreamis=newFileInputStream("jay.txt");Scannerin=newScanner(is);while(in.hasNext()){System.out.println(in.next());}}catch(FileNotFoundExceptione){//e保存异常信息thrownewMyException("文件在哪");}}publicvoidinvokeReadFile()throwsMyException{try{readFile();}catch(MyExceptione){//e保存异常信息thrownewMyException("Filenotfound");}}publicstaticvoidmain(String[]args){TestChainException=newTestChainException();try{t.invokeReadFile();}catch(MyExceptione){e.printStackTrace();}}}//MyException构造函数publicMyException(Stringmessage){super(message);}运行结果如下,没有Throwable原因,所以难找出异常){System.out.println(in.next());}}catch(FileNotFoundExceptione){//e保存异常InformationthrownewMyException("文件在哪里",e);}}publicvoidinvokeReadFile()throwsMyException{try{readFile();}catch(MyExceptione){//e保存异常信息thrownewMyException("Filenotfound",e);}}publicstaticvoidmain(String[]args){TestChainException=newTestChainException();try{t.invokeReadFile();}catch(MyExceptione){e.printStackTrace();}}}//MyException构造函数publicMyException(Stringmessage,Throwablecause){super(message,cause);}9、运行时异常RuntimeException不应该用catch来处理,而是先进行预检,如:NullPointerException处理反例:try{obj.method()}catch(NullPointerExceptione){...}正例:if(obj!=null){...}10、注意异常匹配的顺序,先捕获特定的异常。注意异常的匹配顺序,因为只有第一个匹配到异常的catch块才会被检测到。它将被执行。如果要查看它是NumberFormatException,则抛出NumberFormatException。如果是IllegalArgumentException,则抛出IllegalArgumentException。反例:try{doSomething("testexception");}catch(IllegalArgumentExceptione){log.error(e);}catch(NumberFormatExceptione){log.error(e);}正例:try{doSomething("testexception");}catch(NumberFormatExceptione){log.error(e);}catch(IllegalArgumentExceptione){log.error(e);}原因:因为NumberFormatException是IllegalArgumentException的子类,在反例中,不管是哪个异常,它会匹配IllegalArgumentException,不会再执行,所以不知道是不是NumberFormatException。所以需要优先捕获特定的异常,先放NumberFormatException~
