реализует Closeable или реализует AutoCloseable

128

Я нахожусь в процессе обучения 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 {


}
малас
источник
2
Думаю, все уже было сказано, но, возможно, вам будет интересна следующая статья о примерке ресурсов: docs.oracle.com/javase/tutorial/essential/exceptions/… . Это также может быть полезно для понимания полученных ответов.
crusam

Ответы:

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объекты можно использовать во многих других случаях, чем просто PrintWriters ...
glglgl
3
Ты абсолютно прав. Вопрос был о том, PrintWriterпоэтому я упомянул его, чтобы быть более конкретным.
Кай
7
Зачем описывать ситуацию для Java 6 в контексте AutoCloseable? Лучше покажи try-with-resourcesвместо этого…
ᴠɪɴᴄᴇɴᴛ 01
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 это более старый интерфейс. По какой-то причинеЧтобы сохранить обратную совместимость, разработчики языка решили создать отдельный. Это позволяет не только использовать все Closeableклассы (например, бросание потоков IOException) в try-with-resources, но также позволяет генерировать более общие проверенные исключения из close().

В случае сомнений пользуйтесь AutoCloseable, пользователи вашего класса будут благодарны.

Томаш Нуркевич
источник
107
Причина проста: Closeable.close()бросает IOException. Многие close()методы, которые могут выиграть от try-with-resources, генерируют другие проверенные исключения (например, java.sql.Connection.close()так AutoCloseable.close()бросают Exception. Изменение существующего Closeableконтракта нарушит все существующие приложения / библиотеки, полагающиеся на контракт, который close()только генерирует, IOExceptionа не все (проверенные) исключения.
Отметить Rotteveel
4
@MarkRotteveel: +1, спасибо. Я исправил свой ответ, чтобы отразить ваши предложения и комментарии.
Tomasz Nurkiewicz
9
А также: Closeable.close()требуется быть идемпотентным. AutoCloseable.close()нет, хотя все же настоятельно рекомендуется.
Лукас Эдер
2
Кроме того, не используйте значение по умолчанию public void close( ) throws Exception- используйте более конкретное исключение, если можете (например, IOException)
gerardw
3
Closeableне гарантирует идемпотентность. Это требует идемпотентности в реализации close()метода пользователем. А то, IOExceptionбудет ли он более конкретным / подходящим, зависит от варианта использования.
xdhmoore
71

Closeableextends AutoCloseableи специально предназначен для потоков ввода-вывода: он генерирует IOException вместо Exception и является идемпотентным, тогда как AutoCloseable не предоставляет этой гарантии.

Все это объясняется в документации к обоим интерфейсам.

Реализация AutoCloseable (или Closeable) позволяет использовать класс в качестве ресурса конструкции try-with-resources, представленной в Java 7, что позволяет автоматически закрывать такие ресурсы в конце блока, без необходимости добавления блока finally, который закрывает ресурс явно.

Ваш класс не представляет собой закрываемый ресурс, и нет абсолютно никакого смысла в реализации этого интерфейса: IOTest не может быть закрыт. Невозможно даже создать его экземпляр, поскольку у него нет метода экземпляра. Помните , что средства реализации интерфейса , что есть есть- отношения между классом и интерфейсом. У вас здесь нет таких отношений.

JB Nizet
источник
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 03
В методе close () нам не нужно явно закрывать ресурс? Возможно, есть только оператор печати.
Шайлеш Вагмаре,
@ShaileshWaghmare, да, именно так. но для целей тестирования я упомянул в фрагменте кода.
Лова Читтумури,
@LovaChittumuri Так это будет как this.close()или что-то в коде? Потому что он вызывается автоматически (на всякий
случай
@shailesh Waghmare Хотите проверить меня?
Лова Читтумури,
6

try-with-resourcesЗаявление.

try-with-resources statementЯвляется tryутверждение , что говорит один или несколько ресурсов. 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. Класс BufferedReaderв Java SE 7 и новее реализует интерфейс 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 Programmer Guide II.

Я нашел кое - что о разнице между AutoCloseableпротив Closeable.

AutoCloseableИнтерфейс был введен в Java 7. До этого, другой интерфейс существовал называется Closeable. Это было похоже на то, что хотели разработчики языка, за следующими исключениями:

  • Closeableограничивает тип создаваемого исключения IOException.
  • Closeable требует, чтобы реализации были идемпотентными.

Разработчики языка делают упор на обратную совместимость. Поскольку изменять существующий интерфейс было нежелательно, они сделали новый под названием AutoCloseable. Этот новый интерфейс менее строг, чем Closeable. Поскольку Closeableсоответствует требованиям AutoCloseable, он начал реализовываться, AutoCloseableкогда последний был представлен.

Арвинд Катте
источник
1
Вместо того чтобы говорить, что «Этот новый интерфейс менее строгий, чем Closeable», я бы предложил сказать: «Этот новый интерфейс можно использовать в более общих контекстах, где исключение, созданное во время закрытия, не обязательно является исключением IOException». Во вселенной Java быть «менее строгим» имеет негативный настрой.
fountainhead