当前位置: 首页 > 科技观察

为什么不推荐使用try-catch-finally来处理Java异常?

时间:2023-03-14 11:26:07 科技观察

这篇文章是我最近看的一本书《Effective java》的总结,出自第九篇。为了更透彻的理解,我重新分析了一下,又补充了一些其他的要点。“本文所有示例均基于JDK1.8版本,运行本地代码后运行环境eclipse,本文类名:TryWithResources,下面的堆栈信息也基于此。”人员手动调用close方法关闭,如InputStream、OutputStream和java.sql.Connection。如果您忘记将其关闭,可能会导致严重的性能后果。关闭的方式有很多种。比如finalizer、try-catch-finally、try-with-resources等等。finalizer机制可以关闭,但是它的执行是不可预测的,可能会造成内存泄漏,所以一般不使用。虽然java9也提出了更干净的机制来替代finalizer机制,但是它的执行仍然是不可预测的,所以选择就落在了try-catch-finally和try-with-resources之间。这篇文章是讨论选哪个比较好,不过题目已经给出答案必须try-with-resources。下面就拿这个答案来分析一下为什么推荐try-with-resources而不是try-finally。一、前言在正式分析之前,我们先来看一波finally的执行顺序。1.finally不是必要条件。也就是说,在try-catch-finally中,可以只有try-catch,也可以只有try-finally。2、假设基于try-catch-finally:第一:代码无异常执行顺序:try执行完成->catch不执行->finally执行第二:代码出现异常,catch捕获执行顺序:try执行部分->跳转到catch捕获处理->finally执行第三种:代码有异常catch没有catch:没有catch执行顺序这种情况:try执行部分->finally执行as可以从上面的执行顺序可以看出,finally语句无论在什么情况下都一定会被执行。基于这样的认识,现在我们再分析一下。2、try-finally的缺点我们先来看案例。这个案例来自《Effective java》。现在我们需要关闭资源:staticStringfirstLineOfFile(Stringpath)throwsIOException{BufferedReaderreader=newBufferedReader(newFileReader(path));try{returnreader.readLine();}finally{reader.close();}}关闭一个资源很好,但是如果你添加第二个资源,代码看起来一团糟。staticvoidcopy(Stringsrc,Stringdesc)throwsIOException{InputStreamin=newFileInputStream(src);try{OutputStreamout=newFileOutputStream(desc);byte[]bytes=newbyte[1024];intn;try{while((n=in.read(bytes))!=-1){out.write(bytes,0,n);}}finally{out.close();}}finally{in.close();}}如果有很多类型的资源需要可以关门了,而且数量也很多。该代码太大了。现在总结一下这种方法的缺点:1.关闭资源麻烦,代码复杂。2、对于第一种情况,如果设备异常,那么调用readLine会抛出异常,close方法也会出现异常,这种情况下close异常完全抹杀了readLine异常。异常堆栈跟踪中也根本没有readLine异常的记录。现在来到测试端:基于以上原因,出现了try-with-resources。3、try-with-resources的优点jdk1.7中引入了try-with-resources,可以完美解决以上问题。要使用此结构化资源,您必须首先实现AutoCloseable接口,该接口包含一个返回void的关闭方法。现在Java类库和第三方类库中的很多类和接口都实现或者扩展了AutoCloseable接口,所以我们现在不必去实现它。既然try-with-resources可以解决上面的问题,那我们就来看看如何解决:1.解决复杂代码的问题){byte[]bytes=newbyte[1024];intn;while((n=in.read(bytes))!=-1){out.write(bytes,0,n);}}}可以看出这种方式的代码更简单,也可以快速定位错误。2.解决异常擦除的问题throws异常会被禁止,我们在try-finally处理机制中是看不到的,也不能在stacktrace中打印,但是try-with-resources不同,都会在stacktrace中打印,并表明它们是被禁止的异常,它们也可以通过编写对getSuppressed方法的调用来访问。现在让我们再测试一下。OK,上面的分析基本完成,不过这本书还给出了一个更好的case:returndefaultVal;}}firstLineOfFile方法不会抛出异常,但如果它无法打开文件或无法读取文件,它将返回一个默认值。结论在处理必须关闭的资源时,始终优先使用try-with-resources而不是try-finally。这样得到的代码会更简洁明了,产生的异常也更有价值,这也是try-finally做不到的。