реалізує Closeable або реалізує AutoCloseable


128

Я зараз вивчаю Java, і я не можу знайти жодного хорошого пояснення щодо інтерфейсів implements Closeableта implements AutoCloseableінтерфейсів.

Коли я реалізував interface Closeable, мій IDE Eclipse створив метод 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/… . Це також може бути корисним для розуміння наведених відповідей.
крим

Відповіді:


40

Мені здається, ви не дуже знайомі з інтерфейсами. У коді, який ви опублікували, вам не потрібно реалізовувати AutoCloseable.

Ви повинні лише (або повинні) реалізувати Closeableабо AutoCloseableякщо ви збираєтесь реалізувати свій власний PrintWriter, який обробляє файли чи будь-які інші ресурси, які потрібно закрити.

У вашій реалізації достатньо зателефонувати pw.close(). Ви повинні зробити це остаточно блоком:

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
Чому тільки з a PrintWriter? Особливо AutoClosableоб'єкти можна використовувати в набагато більше обставинах, ніж просто PrintWriters ...
glglgl

3
Ти абсолютно правий. Питання було про те, PrintWriterтому я згадав його, щоб бути більш конкретним.
Кай

7
Навіщо описувати ситуацію з Java 6 в контексті AutoCloseable? Краще покажіть try-with-resourcesзамість цього…
ᴠɪɴᴄᴇɴᴛ

191

AutoCloseable(введено в Java 7) дозволяє використовувати ідіому пробного використання ресурсів :

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) у "пробних ресурсах", але також дозволяє викидати більш загальні перевірені винятки з close().

Якщо ви сумніваєтесь у використанні AutoCloseable, користувачі вашого класу будуть вам вдячні.


107
Причина проста: Closeable.close()кидки IOException. Багато close()методів , які могли б принести користь примірочних з-ресурсів кинути інші перевірені виключення (наприклад , java.sql.Connection.close()так AutoCloseable.close()кидає Exceptionзміна існуючого. CloseableДоговору порушило б всі існуючі додатки / бібліотеки , спираючись на контракт , який close()тільки кидає IOExceptionі не всі (перевірені) виключення.
Марк Rotteveel

4
@MarkRotteveel: +1, дякую. Я виправив свою відповідь, щоб відобразити ваші пропозиції та коментарі.
Томаш Нуркевич

9
А також: Closeable.close()вимагається бути безсильним. AutoCloseable.close()ні, хоча все-таки настійно рекомендується.
Лукас Едер

2
Крім того, не використовуйте за замовчуванням public void close( ) throws Exception- використовуйте більш конкретний виняток, якщо зможете (наприклад, IOException)
gerardw

3
Closeableне гарантує ідентифікацію. Це вимагає ідентичності в реалізації close()методу користувачем. А чи IOExceptionбільш конкретний / підходящий, залежить від випадку використання.
xdhmoore

71

Closeableрозширюється AutoCloseableі спеціально присвячений потокам IO: він викидає IOException замість Exception і є ідентичним, тоді як функція AutoCloseable не дає цієї гарантії.

Це все пояснено в javadoc обох інтерфейсів.

Реалізація функції AutoCloseable (або Closeable) дозволяє використовувати клас як ресурс конструктивної спроби з ресурсами, введеної в Java 7, що дозволяє автоматично закривати такі ресурси в кінці блоку, без необхідності додавати остаточний блок, який закривається ресурс чітко.

Ваш клас не представляє ресурс, що закривається, і немає абсолютно ніякого сенсу в реалізації цього інтерфейсу: IOTest не можна закрити. Це навіть не повинно бути можливим, коли він не має жодного методу екземпляра. Пам'ятайте , що кошти реалізації інтерфейсу , що є є- відносини між класом і інтерфейсом. Тут у вас немає таких стосунків.


5
Просто реалізуйте Clovable для класів, пов’язаних із потоками, та 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 () нам не потрібно чітко закривати ресурс? Можливо, є лише твердження про друк.
Шайлеш Вагмаре

@ShaileshWaghmare так точно. але для цілей тестування я згадую у фрагменті коду.
Lova Chittumuri

@LovaChittumuri Так це буде this.close()щось подібне чи щось у коді ?, тому що воно викликається автоматично. (Просто для переконання)
Shailesh Waghmare

@shailesh Waghmare Ви хочете перевірити мене.
Lova Chittumuri

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();
    }
}

У цьому прикладі ресурс, задекларований в операторі спробу використання ресурсів, є BufferedReader. Заява декларації з’являється в дужках відразу після спробувати ключове слово. Клас BufferedReaderв Java SE 7 і пізніших версіях реалізує інтерфейс java.lang.AutoCloseable. Оскільки BufferedReaderекземпляр оголошений у операторі спробу використання ресурсу, він буде закритий незалежно від того, чи завершується оператор try нормально або різко (в результаті BufferedReader.readLineвикидання методу IOException).

До Java SE 7 ви можете використовувати finallyблок, щоб забезпечити закриття ресурсу незалежно від того, чи завершується операція спробу нормально чи різко. У наступному прикладі 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 Книга.

Я знайшов щось про різницю між AutoCloseablevsCloseable .

AutoCloseableІнтерфейс був введений в Java 7. До цього, інший інтерфейс існував називається Closeable. Це було схоже на те, що хотіли мовні дизайнери, за такими винятками:

  • Closeableобмежує тип виключеного винятку IOException.
  • Closeable вимагає, щоб виконання було ідентичним.

Мовні дизайнери підкреслюють зворотну сумісність. Оскільки зміна існуючого інтерфейсу була небажаною, вони зробили новий під назвою AutoCloseable. Цей новий інтерфейс менш суворий, ніж Closeable. Оскільки Closeableвідповідає вимогам AutoCloseable, вона почала впроваджуватися, AutoCloseableколи була представлена ​​остання.


1
Замість того, щоб сказати, що "Цей новий інтерфейс менш суворий, ніж Closeable", я б запропонував сказати "Цей новий інтерфейс можна використовувати в більш загальних контекстах, де виняток, викинутий під час закриття, не обов'язково є IOException". У Всесвіті Java, будучи "менш суворим", має негативну атмосферу щодо цього.
fountainhead
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.