实现 Closeable 或实现 AutoCloseable
Posted
技术标签:
【中文标题】实现 Closeable 或实现 AutoCloseable【英文标题】:implements Closeable or implements AutoCloseable 【发布时间】:2012-10-19 22:17:28 【问题描述】:我正在学习 Java,在implements Closeable
和implements AutoCloseable
接口上找不到任何好的解释。
当我实现 interface Closeable
时,我的 Eclipse IDE 创建了一个方法 public void close() throws IOException
。
我可以在没有接口的情况下使用pw.close();
关闭流。但是,我无法理解如何使用接口实现close()
方法。而且,这个接口的用途是什么?
我也想知道:如何检查iostream
是否真的关闭了?
我使用的是下面的基本代码
import java.io.*;
public class IOtest implements AutoCloseable
public static void main(String[] args) throws IOException
File file = new File("C:\\test.txt");
PrintWriter pw = new PrintWriter(file);
System.out.println("file has been created");
pw.println("file has been created");
@Override
public void close() throws IOException
【问题讨论】:
我想所有的都已经说了,但也许你对下面关于尝试资源的文章感兴趣:docs.oracle.com/javase/tutorial/essential/exceptions/…。这也可能有助于理解给定的答案。 【参考方案1】:AutoCloseable
(在 Java 7 中引入)使得使用 try-with-resources 成语成为可能:
public class MyResource implements AutoCloseable
public void close() throws Exception
System.out.println("Closing!");
现在你可以说:
try (MyResource res = new MyResource())
// use resource here
JVM 会自动为你调用close()
。
Closeable
是一个较旧的接口。 出于某种原因 为了保持向后兼容性,语言设计者决定单独创建一个。这不仅允许在 try-with-resources 中使用所有 Closeable
类(如抛出 IOException
的流),而且还允许从 close()
抛出更一般的检查异常。
如有疑问,请使用AutoCloseable
,您班级的用户将不胜感激。
【讨论】:
原因很简单:Closeable.close()
抛出IOException
。许多可能受益于 try-with-resources 的 close()
方法会抛出其他检查异常(例如 java.sql.Connection.close()
所以 AutoCloseable.close()
会抛出 Exception
。更改现有的 Closeable
合同将破坏所有现有的应用程序/库依赖close()
仅抛出 IOException
而不是所有(已检查)异常的合同。
@MarkRotteveel:+1,谢谢。我更正了我的答案以反映您的建议和 cmets。
另外:Closeable.close()
必须是幂等的。 AutoCloseable.close()
不是,但仍强烈推荐。
另外,不要使用默认的public void close( ) throws Exception
——如果可以的话,使用更具体的异常(例如 IOException)
Closeable
不保证幂等性。它要求在用户实现close()
方法时具有幂等性。而IOException
是否更具体/更合适取决于用例。【参考方案2】:
Closeable
extends AutoCloseable
,专门用于 IO 流:它抛出 IOException
而不是 Exception
,并且是幂等的,而 AutoCloseable
不提供此保证。
这在两个接口的javadoc中都有解释。
实现AutoCloseable
(或Closeable
)允许将类用作Java 7中引入的try-with-resources构造的资源,它允许在块的末尾自动关闭此类资源,而无需添加finally
块显式关闭资源。
您的类不代表可关闭的资源,实现此接口绝对没有意义:IOTest
无法关闭。甚至不可能实例化它,因为它没有任何实例方法。请记住,实现接口意味着类和接口之间存在 is-a 关系。你这里没有这种关系。
【讨论】:
只需为流相关的类实现 Closable,为其他需要自动关闭功能的类实现 AutoClosable。【参考方案3】:在我看来,您对接口不是很熟悉。在您发布的代码中,您无需实现AutoCloseable
。
如果您即将实现自己的PrintWriter
,您只需(或应该)实现Closeable
或AutoCloseable
,它处理文件或任何其他需要关闭的资源。
在您的实现中,调用pw.close()
就足够了。您应该在 finally 块中执行此操作:
PrintWriter pw = null;
try
File file = new File("C:\\test.txt");
pw = new PrintWriter(file);
catch (IOException e)
System.out.println("bad things happen");
finally
if (pw != null)
try
pw.close();
catch (IOException e)
上面的代码与 Java 6 相关。在 Java 7 中,这可以更优雅地完成(参见 this answer)。
【讨论】:
为什么只使用PrintWriter
?特别是 AutoClosable
对象可以在更多情况下使用,而不仅仅是 PrintWriter
s...
你是绝对正确的。问题是关于PrintWriter
,所以我提到它更具体。
为什么要在AutoCloseable
的上下文中描述Java 6 的情况?最好显示 try-with-resources
来代替……【参考方案4】:
这是一个小例子
public class TryWithResource
public static void main(String[] args)
try (TestMe r = new TestMe())
r.generalTest();
catch(Exception e)
System.out.println("From Exception Block");
finally
System.out.println("From Final Block");
public class TestMe implements AutoCloseable
@Override
public void close() throws Exception
System.out.println(" From Close - AutoCloseable ");
public void generalTest()
System.out.println(" GeneralTest ");
这是输出:
GeneralTest
From Close - AutoCloseable
From Final Block
【讨论】:
最好也写输出,这样短代码就不需要试用项目了。 在close()方法中,我们不需要显式关闭资源吗?也许只有打印语句。 @ShaileshWaghmare 是的。但出于测试目的,我在代码片段中提到了。 @LovaChittumuri 那么它会像this.close()
还是代码中的东西?因为它是自动调用的。(只是为了确定)
@shailesh Waghmare 你想测试我吗?【参考方案5】:
最近我读了一本 Java SE 8 Programmer Guide ii Book。
我发现了 AutoCloseable
与 Closeable
之间的区别。
AutoCloseable
接口是在 Java 7 中引入的。在此之前,另一个接口
存在称为Closeable
。它类似于语言设计者想要的,具有
以下例外:
Closeable
将抛出的异常类型限制为IOException
。
Closeable
要求实现是幂等的。
语言设计者强调向后兼容性。由于改变现有
界面不受欢迎,他们制作了一个名为AutoCloseable
的新界面。这个新
接口没有Closeable
那么严格。由于Closeable
符合要求
AutoCloseable
,它是在引入 AutoCloseable
时开始实现的。
【讨论】:
与其说“这个新接口没有Closeable
那么严格”,我建议说“这个新接口可以在更一般的上下文中使用,在关闭期间抛出的异常不是必然是一个 IOException”。在 Java 世界中,“不那么严格”有负面影响。【参考方案6】:
try-with-resources
声明。
try-with-resources statement
是声明一个或多个资源的try
语句。 resource
是一个在程序完成后必须关闭的对象。 try-with-resources statement
确保每个资源在语句结束时关闭。任何实现java.lang.AutoCloseable
的对象,包括所有实现java.io.Closeable
的对象,都可以用作资源。
以下示例从文件中读取第一行。它使用BufferedReader
的实例从文件中读取数据。 BufferedReader
是一个资源,程序结束后必须关闭它:
static String readFirstLineFromFile(String path) throws IOException
try (BufferedReader br =
new BufferedReader(new FileReader(path)))
return br.readLine();
在本例中,try-with-resources 语句中声明的资源是 BufferedReader。声明语句紧跟在 try 关键字之后的括号内。在 Java SE 7 及更高版本中,类 BufferedReader
实现了接口 java.lang.AutoCloseable
。因为BufferedReader
实例是在try-with-resource 语句中声明的,所以无论try 语句是正常完成还是突然完成(作为BufferedReader.readLine
方法抛出IOException
的结果),它都会被关闭。
在 Java SE 7 之前,您可以使用 finally
块来确保关闭资源,无论 try 语句是正常完成还是突然完成。以下示例使用 finally
块而不是 try-with-resources
语句:
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException
BufferedReader br = new BufferedReader(new FileReader(path));
try
return br.readLine();
finally
if (br != null) br.close();
请refer to the docs。
【讨论】:
以上是关于实现 Closeable 或实现 AutoCloseable的主要内容,如果未能解决你的问题,请参考以下文章