“全栈2019”Java异常第二十二章:try-with-resources语句详解

182 阅读11分钟

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境

  • JDK v11
  • IntelliJ IDEA v2018.3

友情提示

  • 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
  • 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!

1.程序正在使用,操作无法完成

在开始今天的内容之前,想请大家看一张图:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

这张图对于大家来说应该不陌生,都有遇见过。这是我们在程序已经打开的情况下,还要去删除程序所在的目录内容产生的提示框

对于这张图的重点,我用红色部分标注出来:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

被标注的地方有三处:“文件正在使用”、“操作无法完成,因为文件已在xxx中打开”和“请关闭文件并重试”。

有小伙伴就问了:这和今天的内容有关系吗?

这和今天的内容有关系,而且还很重要,请大家稍安勿躁,耐心理解其中的用意。

好,接下来,我们来分别看看这三处所对应的意思是什么。

文件正在使用:

表示文件正在被某个程序使用中。

操作无法完成,因为文件已在xxx中打开:

表示正在被使用中的文件不能被其他程序所操作。

请关闭文件并重试:

表示我们要等待程序使用完并释放对此文件,也就是程序使用完文件以后要关闭这个文件。然后我们在重新试试上一次的操作。

说了这么多,到底想表达什么?

想表达的是,我们的程序使用完一个文件后,必须要关闭它。

其实不光是文件,还有其他很多对象,在程序中使用完之后都需要将其关闭。

为了方便大家记住这个例子,我们来简化一下这个例子步骤:

  1. 打开资源。
  2. 使用资源。
  3. 关闭资源。

下面我们开始介绍try-with-resources语句。

2.try-with-resources语句是什么?

上一小节中的“我们的程序使用完一个文件后,必须要关闭它。”这句话和我们的try-with-resources语句密切相关。所以,接下来我们看看try-with-resources语句定义:

try-with-resources语句是一个声明一个或多个资源的try语句。

先不着急理解try-with-resources语句定义,我们会分词解释说明的。

什么是“资源”?

在分词解释说明之前,先来理解“try-with-resources语句是一个声明一个或多个资源的try语句。”中的资源是什么:

资源是在程序完成后必须关闭的对象。

请大家再结合上一小节的例子来理解资源的定义:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

在这个例子中,文件“setup.exe”就是资源,因为它必须在程序使用完要关闭。大家明白什么是资源了吗?

还不明白的话,我们来个Java程序感受一下:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

这个例子对大家来说不陌生了,例子内容是读取文本文件内容。前面好几章内容都出现过,简单的梳理一下步骤:

  1. 打开文本文件。
  2. 使用文本文件(读取文本文件内容)。
  3. 关闭文本文本。

那么,对应的,文本文件就是资源

在这个Java例子中,哪一步是关闭资源呢?请看:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

图中红色框中部分就是关闭资源操作。即“fileReader.close();”,俗称关流

资源是在程序完成后必须关闭的对象。”这句话提到“必须关闭”四个字,也就是说这个关闭动作必须要做,把必须要执行的操作放在哪最合适?

通过前面的学习,我们知道必须要执行的操作最好是放在finally代码块里面

我们的程序也是这么干的:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

之前一直不理解为什么要这么做的小伙伴,今天理解了吧。

为什么是必须关闭?

这个问题来自于“资源是在程序完成后必须关闭的对象。”这句话中的“必须关闭”四个字。解答这个问题并不难,还是上一小节的例子:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

一目了然,你不关闭程序正在使用的文件,其他对该文件的操作就无法完成,比如删除、移动等操作。所以,我们程序在使用完文件等资源后,一定要关闭其资源。

这里还要给大家介绍一个和关闭互换的词,叫“释放”,我们的“关闭资源”也能称之为“释放资源”。

我们还可以把程序对资源的使用看作是一种引用,程序使用完毕后要释放其引用

所以,我们可以把之前的三种操作:

  1. 打开资源。
  2. 使用资源。
  3. 关闭资源。

换成新的理解:

  1. 引用资源。
  2. 使用资源。
  3. 释放资源。

分三部分解释try-with-resources语句定义

将“try-with-resources语句是一个声明一个或多个资源的try语句。 ”分为三部分来看:

try-with-resources语句是一个 ”、“声明一个或多个资源的 ”和“try语句

第一部分,try-with-resources语句是一个

从这一部分我们可以知道try-with-resources是一个语句。语句的话肯定是要有规范和规则的,所以后面两部分就说明了这两点。

第二部分,声明一个或多个资源的

从这一部分我们了解到try-with-resources语句是跟资源相关的

说到资源,就自然而然有三种操作:引用资源,使用资源,释放资源。

这三种操作try-with-resources语句都包括吗?

除了使用资源不包括以外其他两个都包括,从“声明一个或多个资源的”这句话看出,我们的try-with-resources语句包括引用资源。

第三部分,try语句

这个我们熟,就是try代码块:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

不是,上面是try代码块,而定义中说的是try语句。有区别的,语句是有一对小括号()的,所以,try-with-resources语句的样子就浮出水面了:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

至此,try-with-resources语句定义部分讲解完毕,下面讲解为什么要使用try-with-resources语句。

演示try-with-resources语句的例子在第3小节,也就是下一小节。

3.为什么要使用try-with-resources语句?

我们的try-with-resources语句有一个特别特别重要的特性:

try-with-resources语句确保在语句结束时关闭每个资源。

从这个特性来看,try-with-resources语句有finally代码块作用,实际上它的出现就是让我们在关闭资源的时候多了一个选择,不再是只有finally一种选择。

这里,我们还是举例来感受一下try-with-resources语句及它的特性。通过“未使用try-with-resources语句”和“使用try-with-resources语句”两个例子对比感受一下try-with-resources语句给我们带来的便利。

准备工作

在写例子之前,我们做一下简单的准备工作,请大家打开IntelliJ IDEA,然后使用IntelliJ IDEA创建一个Java项目或打开一个已存在的Java项目,然后在项目的src目录下创建一个“error.txt”的文本文件

“全栈2019”Java异常第二十二章:try-with-resources语句详解

接着,在“error.txt”文本文件中写入内容“abc”

“全栈2019”Java异常第二十二章:try-with-resources语句详解

最后,右键“error.txt”文本文件,选择“Copy Path”

“全栈2019”Java异常第二十二章:try-with-resources语句详解

复制“error.txt”文本文件路径备用。

未使用try-with-resources语句

演示:

请读取“error.txt”文本文件内容。

请观察程序代码及结果。

代码:

Main类:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

结果:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

从运行结果来看,符合我们的预期,程序代码没有问题。这个程序呢,前几章分析好几遍了,这里就不再赘述,不清楚的小伙伴可以看看《“全栈2019”Java异常第五章:一定会被执行的finally代码块》一章。

这是未使用try-with-resources语句的情况,下面看看使用try-with-resources语句的情况。

使用try-with-resources语句

演示:

请读取“error.txt”文本文件内容。

请观察程序代码及结果。

代码:

Main类:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

结果:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

从运行结果来看,和上一小节的结果一样,符合预期。

“全栈2019”Java异常第二十二章:try-with-resources语句详解

很直观的感受就是使用try-with-resources语句例子程序代码更少,未使用try-with-resources语句程序代码比使用try-with-resources语句程序代码多了14行。其实它们之间的对比不仅仅是代码的多与少,更多的是看try-with-resources语句实现了什么功能,才省下了这几行代码。

我们来看try-with-resources语句省下的代码片段:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

该代码片段做了什么事情?

做的事情是释放资源。调用其释放资源对象的方法。

我们再来看try-with-resources语句中做了什么事情:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

做的事情是引用资源。实际上是创建资源对象

综上所述,try-with-resources语句做了两件事:引用资源和释放资源

我们再来回顾本节例子,首先在try-with-resources语句中引用资源(创建资源对象):

“全栈2019”Java异常第二十二章:try-with-resources语句详解

然后在try代码块里面直接使用try-with-resources语句中的资源对象:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

程序中该catch(捕获)的异常还是得catch(捕获):

“全栈2019”Java异常第二十二章:try-with-resources语句详解

因为我们try-with-resources语句会在整个语句执行完毕后自动释放资源,所以我们不必书写finally代码块及释放资源代码。

4.有了try-with-resources语句,是不是不必再使用finally代码块了?

非也,不是这样的,我们有了try-with-resources语句,只是给了我们一种更好的选择,而不是去完全替代finally,而且从代码规范来看:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

我们的finally代码块还是可以跟在后面,它还是那个finally,它依然有它发挥的作用,应该和try-with-resources语句相互配合,写出更加优秀高效的代码。

5.是不是所有资源对象都可以放在try-with-resources语句中?

不是,只有实现java.lang.AutoCloseable的任何对象(包括实现java.io.Closeable的所有对象)才可以

像例子中的FileReader对象,它自身没有实现AutoCloseable或Closeable接口,但是它父类的父类Reader实现了Closeable接口InputStreamReader:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

FileReader继承自InputStreamReader

“全栈2019”Java异常第二十二章:try-with-resources语句详解

InputStreamReader继承自Reader

“全栈2019”Java异常第二十二章:try-with-resources语句详解

Reader实现了Closeable接口

java.lang.AutoCloseable和java.io.Closeable是两个接口,我们会在后续IO流系列中讲解它们,但是它们是try-with-resources语句的核心

java.lang.AutoCloseable接口:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

java.io.Closeable接口是继承自AutoCloseable接口的:

“全栈2019”Java异常第二十二章:try-with-resources语句详解

AutoCloseable翻译过来就是可自动关闭的。我们大家应该可以从中就能感受到,只要资源对象实现了AutoCloseable接口,再配合try-with-resources语句,就能实现自动释放资源的操作。

同样的,因为Closeable接口继承自AutoCloseable接口,所以实现Closeable接口也同样具备自动关闭资源的特性。

总结

  • try-with-resources语句是一个声明一个或多个资源的try语句。
  • 资源是在程序完成后必须关闭的对象。
  • 我们有了try-with-resources语句,只是给了我们一种更好的选择,而不是去完全替代finally。
  • 我们的finally代码块还是可以跟在后面,它还是那个finally,它依然有它发挥的作用,应该和try-with-resources语句相互配合,写出更加优秀高效的代码。
  • 只有实现java.lang.AutoCloseable的任何对象(包括实现java.io.Closeable的所有对象)才可以放在try-with-resources语句中。

至此,Java中try-with-resources语句相关内容讲解先告一段落,更多内容请持续关注。

答疑

如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。

上一章

“全栈2019”Java异常第二十一章:finally不被执行的情况

下一章

  • 本章为《“全栈2019”Java异常》系列最后一章,接下来是《“全栈2019”Java多线程》系列。
  • 《“全栈2019”Java异常》系列全部文章都在《“全栈2019”22篇Java异常学习资料及总结》一文中。

学习小组

加入同步学习小组,共同交流与进步。

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。

全栈工程师学习计划

关注我们,加入“全栈工程师学习计划”。

“全栈2019”Java异常第二十二章:try-with-resources语句详解

版权声明

原创不易,未经允许不得转载!