实现Closeable或实现AutoCloseable


127

我正在学习Java,但是在implements Closeableimplements AutoCloseable接口上找不到任何好的解释。

当我实现an时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 {


}

2
我认为已经讲完了所有内容,但是也许您对以下有关尝试使用资源的文章感兴趣:docs.oracle.com/javase/tutorial/essential/exceptions/…。这也可能有助于理解给定的答案。
crusam 2012年

Answers:


40

在我看来,您对接口不是很熟悉。在您发布的代码中,您无需实现AutoCloseable

您仅需要(或应该)实施,Closeable或者AutoCloseable如果您将要实施自己的PrintWriter,该文件可以处理需要关闭的文件或任何其他资源。

在您的实现中,只需调用即可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中,可以更优雅地完成此操作(请参阅此答案)。


3
为什么只用一个PrintWriter?特别是AutoClosable对象可以在更多情况下使用,而不仅仅是PrintWriter……
glglgl 2015年

3
你是绝对正确的。问题是关于这个的,PrintWriter所以我提到了更具体的问题。
2015年

7
为什么要在上下文中描述Java 6的情况AutoCloseable?更好的显示try-with-resources,而不是...
ᴠɪɴᴄᴇɴᴛ

191

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类(如stream throwing IOException),而且还允许从抛出更一般的检查异常close()

如有疑问,请使用AutoCloseable,您班上的用户将不胜感激。


107
原因很简单:Closeable.close()throws IOException。许多close()可能会从尝试资源中受益的方法会引发其他检查的异常(例如java.sql.Connection.close()AutoCloseable.close()引发Exception。更改现有Closeable合同会破坏所有现有的应用程序/库,而依赖于close()仅引发IOException而非所有(检查的)异常的合同。)
标记Rotteveel 2012年

4
@MarkRotteveel:+1,谢谢。我更正了我的答案,以反映您的建议和意见。
Tomasz Nurkiewicz 2012年

9
并且:Closeable.close()必须是幂等的。AutoCloseable.close()不是,尽管仍然强烈建议使用。
卢卡斯·埃德

2
另外,请勿使用默认值public void close( ) throws Exception-如果可以的话,请使用更具体的例外情况(例如IOException)
gerardw 2014年

3
Closeable保证幂等。它要求用户在该close()方法的实现中具有幂等性。以及是否IOException更具体/合适取决于用例。
xdhmoore

70

Closeableextend AutoCloseable,专门用于IO流:它抛出IOException而不是Exception,并且是幂等的,而AutoCloseable不提供此保证。

这两个接口的javadoc中都对此进行了解释。

实现AutoCloseable(或Closeable)允许将一个类用作Java 7中引入的try-with-resources构造的资源,该类允许在块的末尾自动关闭此类资源,而不必添加finally块来关闭明确地资源。

您的类并不表示可关闭的资源,并且实现此接口绝对没有意义:IOTest无法关闭。甚至不可能实例化它,因为它没有任何实例方法。请记住,实现接口意味着类与接口之间存在is -a关系。您在这里没有这种关系。


5
只需为与流相关的类实现Closable,为其他需要自动关闭功能的类实现AutoClosable
lospejos

7

这是个小例子

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

最好也编写输出,这样就不需要这样的简短代码的试用项目。
raxetul

在close()方法中,我们不需要显式关闭资源吗?也许只有打印语句。
Shailesh Waghmare

@ShaileshWaghmare是的。但是出于测试目的,我在代码片段中提到了。
Lova Chittumuri

@LovaChittumuri那么,它会像this.close()代码一样吗?,因为它会被自动调用。(请确保)
Shailesh Waghmare

@shailesh Waghmare您想测试我吗。
Lova Chittumuri

6

try-with-resources声明。

try-with-resources statementtry,声明一个或多个资源声明。A 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关键字之后的括号内。BufferedReaderJava SE 7及更高版本中的类实现interface 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();
    }

}

参考文档


6

最近,我阅读了Java SE 8程序员指南ii。

我发现一些有关之间的差异AutoCloseableVS Closeable

AutoCloseable接口是Java 7中引入的。在此之前,存在另一个名为的接口Closeable。它与语言设计师想要的类似,但有以下例外:

  • Closeable将抛出的异常类型限制为IOException
  • Closeable 要求实现是幂等的。

语言设计师强调向后兼容性。由于不希望更改现有接口,因此他们创建了一个名为的新接口AutoCloseable。此新界面不如严格Closeable。由于Closeable符合的要求 AutoCloseable,因此AutoCloseable在引入后者时就开始实施。


1
Closeable我建议您说“可以在更一般的上下文中使用此新接口,因为在关闭期间抛出的异常不一定是IOException” ,而不是说“此新接口没有那么严格”。在Java领域中,“不严格”会对它产生负面影响。
水源
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.