implementa Chiudibile o implementa Chiudibile automaticamente


128

Sto imparando Java e non riesco a trovare alcuna buona spiegazione su implements Closeablee sulle implements AutoCloseableinterfacce.

Quando ho implementato un interface Closeable, il mio IDE Eclipse ha creato un metodo public void close() throws IOException.

Posso chiudere il flusso usando pw.close();senza l'interfaccia. Ma non riesco a capire come posso implementare il close()metodo usando l'interfaccia. E qual è lo scopo di questa interfaccia?

Inoltre vorrei sapere: come posso verificare se è IOstreamstato veramente chiuso?

Stavo usando il codice di base qui sotto

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
Penso che sia già stato detto tutto, ma forse sei interessato al seguente articolo su provare su risorse: docs.oracle.com/javase/tutorial/essential/exceptions/… . Questo potrebbe anche essere utile per comprendere le risposte fornite.
Crusam,

Risposte:


40

Mi sembra che tu non abbia molta familiarità con le interfacce. Nel codice che hai pubblicato, non è necessario implementarlo AutoCloseable.

Devi solo (o dovresti) implementare Closeableo AutoCloseablese stai per implementare il tuo PrintWriter, che gestisce i file o qualsiasi altra risorsa che deve essere chiusa.

Nella tua implementazione, è sufficiente chiamare pw.close(). Dovresti farlo in un blocco finalmente:

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) {
      }
   }
}

Il codice sopra è relativo a Java 6. In Java 7 questo può essere fatto in modo più elegante (vedi questa risposta ).


3
Perché solo con un PrintWriter? Soprattutto gli AutoClosableoggetti possono essere usati in molte altre circostanze oltre al semplice PrintWriter...
glglgl,

3
Hai assolutamente ragione. La domanda riguardava PrintWriterquindi l'ho menzionato per essere più specifico.
Kai,

7
Perché descrivere la situazione per Java 6 nel contesto di AutoCloseable? Meglio mostrare un try-with-resourcesinvece ...
ᴠɪɴᴄᴇɴᴛ

191

AutoCloseable(introdotto in Java 7) consente di utilizzare il linguaggio try-with-resources :

public class MyResource implements AutoCloseable {

    public void close() throws Exception {
        System.out.println("Closing!");
    }

}

Ora puoi dire:

try (MyResource res = new MyResource()) {
    // use resource here
}

e JVM chiamerà close()automaticamente per te.

Closeable è un'interfaccia più vecchia. Per qualche ragionePer preservare la compatibilità con le versioni precedenti, i progettisti del linguaggio hanno deciso di crearne uno separato. Ciò consente non solo tutte le Closeableclassi (come il lancio di flussi IOException) di essere utilizzate nelle risorse di prova, ma consente anche di generare eccezioni verificate più generali da close().

In caso di dubbi, utilizzare AutoCloseable, gli utenti della tua classe ti saranno grati.


107
Il motivo è semplice: Closeable.close()genera IOException. Un sacco di close()metodi che potrebbero beneficiare di try-with-risorse lanciano altre eccezioni controllate (ad esempio, java.sql.Connection.close()in modo AutoCloseable.close()getta ExceptionModifica della esistente. CloseableContratto sarebbe rompere tutte le applicazioni esistenti / biblioteca basandosi sul contratto che close()solo tiri IOExceptione non tutti) eccezioni controllate (.
Mark Rotteveel,

4
@MarkRotteveel: +1, grazie. Ho corretto la mia risposta per riflettere i tuoi suggerimenti e commenti.
Tomasz Nurkiewicz,

9
E anche: Closeable.close()è necessario essere idempotenti. AutoCloseable.close()non lo è, sebbene sia ancora fortemente raccomandato.
Lukas Eder,

2
Inoltre, non utilizzare l'impostazione predefinita public void close( ) throws Exception: utilizzare un'eccezione più specifica se è possibile (ad esempio IOException)
gerardw,

3
Closeablenon garantisce l' idempotenza. Si richiede idempotence nell'attuazione di un utente del close()metodo. E se IOExceptionè più specifico / appropriato dipende dal caso d'uso.
xdhmoore,

71

Closeablesi estende AutoCloseableed è specificamente dedicato ai flussi IO: genera IOException invece di Exception ed è idempotente, mentre AutoCloseable non fornisce questa garanzia.

Tutto ciò è spiegato nel javadoc di entrambe le interfacce.

L'implementazione di AutoCloseable (o Closeable) consente di utilizzare una classe come risorsa del costrutto try-with-resources introdotto in Java 7, che consente di chiudere automaticamente tali risorse alla fine di un blocco, senza dover aggiungere un blocco infine che si chiude la risorsa esplicitamente.

La tua classe non rappresenta una risorsa chiudibile e non ha assolutamente senso implementare questa interfaccia: un IOTest non può essere chiuso. Non dovrebbe nemmeno essere possibile istanziarlo, poiché non ha alcun metodo di istanza. Ricorda che l'implementazione di un'interfaccia significa che esiste una relazione is-a tra la classe e l'interfaccia. Non hai una relazione del genere qui.


5
Basta implementare Closable per le classi correlate agli stream e AutoClosable per gli altri che richiedono la funzione di chiusura automatica.
Lospejos,

7

Ecco il piccolo esempio

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

Ecco l'output:

GeneralTest 
From Close -  AutoCloseable  
From Final Block

È meglio scrivere anche l'output, quindi non sarà necessario un progetto di prova per un codice così corto.
raxetul,

Nel metodo close (), non è necessario chiudere esplicitamente la risorsa? C'è forse solo un'istruzione di stampa.
Shailesh Waghmare,

@ShaileshWaghmare sì, esattamente. ma ai fini del test ho citato nel codice snip.
Lova Chittumuri,

@LovaChittumuri Quindi sarà come this.close()o qualcosa del codice? Perché è chiamato automaticamente (solo per essere sicuri)
Shailesh Waghmare

@shailesh Waghmare Ti piacerebbe mettermi alla prova.
Lova Chittumuri,

6

La try-with-resourcesdichiarazione.

Il try-with-resources statementè una trydichiarazione che dichiara una o più risorse. A resourceè un oggetto che deve essere chiuso al termine del programma. Il try-with-resources statementassicura che ogni risorsa sia chiuso alla fine dell'istruzione. Qualsiasi oggetto che implementa java.lang.AutoCloseable, che include tutti gli oggetti che implementano java.io.Closeable, può essere utilizzato come risorsa.

L'esempio seguente legge la prima riga da un file. Utilizza un'istanza di BufferedReaderper leggere i dati dal file. BufferedReaderè una risorsa che deve essere chiusa al termine del programma:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

In questo esempio, la risorsa dichiarata nell'istruzione try-with-resources è BufferedReader. La dichiarazione di dichiarazione appare tra parentesi immediatamente dopo la parola chiave try. La classe BufferedReader, in Java SE 7 e versioni successive, implementa l'interfaccia java.lang.AutoCloseable. Poiché l' BufferedReaderistanza viene dichiarata in un'istruzione try-with-resource, verrà chiusa indipendentemente dal fatto che l'istruzione try venga completata normalmente o bruscamente (come risultato del metodo che BufferedReader.readLinelancia un IOException).

Prima di Java SE 7, è possibile utilizzare un finallyblocco per assicurarsi che una risorsa sia chiusa indipendentemente dal fatto che l'istruzione try venga completata normalmente o bruscamente. L'esempio seguente utilizza un finallyblocco anziché try-with-resourcesun'istruzione:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }

}

Si prega di fare riferimento alla documentazione .


6

Di recente ho letto un libro del Manuale del programmatore Java SE 8.

Ho trovato qualcosa circa la differenza tra AutoCloseablevs Closeable.

L' AutoCloseableinterfaccia è stata introdotta in Java 7. Prima di allora esisteva un'altra interfaccia chiamata Closeable. Era simile a quello che volevano i progettisti del linguaggio, con le seguenti eccezioni:

  • Closeablelimita il tipo di eccezione generata IOException.
  • Closeable richiede che le implementazioni siano idempotenti.

I progettisti linguistici sottolineano la compatibilità con le versioni precedenti. Dato che cambiare l'interfaccia esistente era indesiderabile, ne fecero una nuova chiamata AutoCloseable. Questa nuova interfaccia è meno severa di Closeable. Dal momento che Closeablesoddisfa i requisiti per AutoCloseable, ha iniziato l'implementazione AutoCloseablequando è stato introdotto quest'ultimo.


1
Invece di dire che "Questa nuova interfaccia è meno severa di Closeable", suggerirei di dire "Questa nuova interfaccia può essere utilizzata in contesti più generali, in cui l'eccezione generata durante la chiusura non è necessariamente una IOException". Nell'universo Java, essere "meno severi" ha un'atmosfera negativa al riguardo.
Fountainhead,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.