implementa Closeable ou implementa AutoCloseable

128

Estou no processo de aprender Java e não consigo encontrar nenhuma boa explicação sobre implements Closeableas implements AutoCloseableinterfaces e.

Quando implementei um interface Closeable, meu Eclipse IDE criou um método public void close() throws IOException.

Eu posso fechar o fluxo usando pw.close();sem a interface. Mas não consigo entender como implementar o close()método usando a interface. E qual é o objetivo dessa interface?

Também gostaria de saber: como posso verificar se IOstreamfoi realmente fechado?

Eu estava usando o código básico abaixo

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 {


}
malas
fonte
2
Acho que tudo já foi dito, mas talvez você esteja interessado no seguinte artigo sobre a tentativa de obter recursos: docs.oracle.com/javase/tutorial/essential/exceptions/… . Isso também pode ser útil para entender as respostas fornecidas.
crusam

Respostas:

40

Parece-me que você não está muito familiarizado com interfaces. No código que você postou, você não precisa implementar AutoCloseable.

Você só precisa (ou deve) implementar Closeableou AutoCloseablese está prestes a implementar o seu próprio PrintWriter, que lida com arquivos ou quaisquer outros recursos que precisam ser fechados.

Na sua implementação, basta ligar pw.close(). Você deve fazer isso em um bloco 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) {
      }
   }
}

O código acima está relacionado ao Java 6. No Java 7, isso pode ser feito de maneira mais elegante (consulte esta resposta ).

Kai
fonte
3
Por que apenas com um PrintWriter? Especialmente AutoClosableos objetos podem ser usados em muitas circunstâncias mais do que apenas PrintWriters ...
glglgl
3
Você está absolutamente certo. A questão era sobre, PrintWriterentão eu mencionei que era mais específico.
Kai
7
Por que descrever a situação do Java 6 no contexto de AutoCloseable? Melhor mostrar uma try-with-resourcesvez…
#:
191

AutoCloseable(introduzido no Java 7) torna possível usar o idioma try-with-resources :

public class MyResource implements AutoCloseable {

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

}

Agora você pode dizer:

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

e a JVM ligará close()automaticamente para você.

Closeable é uma interface mais antiga. Por algum motivoPara preservar a compatibilidade com versões anteriores, os designers de idiomas decidiram criar um separado. Isso permite que não apenas todas as Closeableclasses (como lançamento de fluxos IOException) sejam usadas no try-with-resources, mas também permite lançar exceções verificadas mais gerais close().

Em caso de dúvida, use AutoCloseable, os usuários de sua classe ficarão agradecidos.

Tomasz Nurkiewicz
fonte
107
A razão é simples: Closeable.close()joga IOException. Um monte de close()métodos que poderiam se beneficiar de try-com-recursos lançar outras exceções verificadas (por exemplo, java.sql.Connection.close()por isso AutoCloseable.close()joga ExceptionAlterar o existente. CloseableContrato iria quebrar todos os aplicativos existentes / biblioteca contando com o contrato que close()só põe IOExceptione não todas as exceções (marcado).
Mark Rotteveel
4
@ MarkRotteveel: +1, obrigado. Corrigi minha resposta para refletir suas sugestões e comentários.
Tomasz Nurkiewicz 30/10/12
9
E também: Closeable.close()é necessário ser idempotente. AutoCloseable.close()não é, embora ainda seja fortemente recomendado.
Lukas Eder
2
Além disso, não use o padrão public void close( ) throws Exception- use uma exceção mais específico, se você pode (e..g IOException)
gerardw
3
Closeablenão garante idempotência. Ele requer idempotência na implementação de um usuário do close()método. E se IOExceptioné mais específico / apropriado depende do caso de uso.
Xdhmoore 15/07/2015
71

Closeableestende AutoCloseablee é dedicado especificamente aos fluxos de IO: lança IOException em vez de Exception e é idempotente, enquanto o AutoCloseable não fornece essa garantia.

Tudo isso é explicado no javadoc de ambas as interfaces.

A implementação do AutoCloseable (ou Closeable) permite que uma classe seja usada como um recurso da construção try-with-resources introduzida no Java 7, que permite fechar esses recursos automaticamente no final de um bloco, sem precisar adicionar um bloco final que fecha o recurso explicitamente.

Sua classe não representa um recurso que pode ser fechado e não há absolutamente nenhum sentido em implementar essa interface: um IOTest não pode ser fechado. Nem deveria ser possível instanciar, pois ele não possui nenhum método de instância. Lembre-se de que implementar uma interface significa que existe um relacionamento entre a classe e a interface. Você não tem esse relacionamento aqui.

JB Nizet
fonte
5
Basta implementar o Closable para classes relacionadas a fluxos e o AutoClosable para outros, que requer o recurso de fechamento automático.
lospejos
7

Aqui está o pequeno exemplo

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

Aqui está a saída:

GeneralTest 
From Close -  AutoCloseable  
From Final Block
Lova Chittumuri
fonte
É melhor escrever a saída também, assim não haverá necessidade de um projeto de teste para um código tão curto.
raxetul
No método close (), não precisamos fechar o recurso explicitamente? Talvez haja apenas uma declaração impressa.
Shailesh Waghmare 03/02
@ShaileshWaghmare yes exatamente. mas, para fins de teste, mencionei no trecho de código.
Lova Chittumuri 03/02
@LovaChittumuri Por isso, será como this.close()ou algo em código ?, porque ele é chamado automaticamente (só para ter certeza).
Shailesh Waghmare
@shailesh Waghmare Gostaria de me testar.
Lova Chittumuri
6

A try-with-resourcesdeclaração.

O try-with-resources statementé uma trydeclaração que declara um ou mais recursos. A resourceé um objeto que deve ser fechado após o término do programa. O try-with-resources statementassegura que cada recurso é fechada no final da instrução. Qualquer objeto implementado java.lang.AutoCloseable, que inclui todos os objetos implementados java.io.Closeable, pode ser usado como um recurso.

O exemplo a seguir lê a primeira linha de um arquivo. Ele usa uma instância de BufferedReaderpara ler dados do arquivo. BufferedReaderé um recurso que deve ser fechado após a conclusão do programa:

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

Neste exemplo, o recurso declarado na instrução try-with-resources é um BufferedReader. A declaração de declaração aparece entre parênteses imediatamente após a palavra-chave try. A classeBufferedReader , no Java SE 7 e posterior, implementa a interface java.lang.AutoCloseable. Como a BufferedReaderinstância é declarada em uma instrução try-with-resource, ela será fechada, independentemente de a instrução try ser concluída normalmente ou abruptamente (como resultado do método que BufferedReader.readLinegera um IOException).

Antes do Java SE 7, você pode usar um finally bloco para garantir que um recurso seja fechado, independentemente de a instrução try ser concluída normalmente ou abruptamente. O exemplo a seguir usa um finallybloco em vez de uma try-with-resourcesinstrução:

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

}

Por favor, consulte os documentos .

inder
fonte
6

Recentemente, li um livro do Java SE 8 Programmer Guide ii.

Eu encontrei algo sobre a diferença entre AutoCloseablevsCloseable .

A AutoCloseableinterface foi introduzida no Java 7. Antes disso, existia outra interface chamada Closeable. Era semelhante ao que os designers de linguagem desejavam, com as seguintes exceções:

  • Closeablerestringe o tipo de exceção lançada para IOException.
  • Closeable requer implementações para ser idempotente.

Os designers de idiomas enfatizam a compatibilidade com versões anteriores. Como alterar a interface existente era indesejável, eles criaram uma nova chamada AutoCloseable. Essa nova interface é menos rigorosa que Closeable. Uma vez que Closeableatende aos requisitos para AutoCloseable, começou a implementar AutoCloseablequando o último foi introduzido.

Arvind Katte
fonte
1
Em vez de dizer que "Esta nova interface é menos rigorosa que Closeable", sugiro dizer "Esta nova interface pode ser usada em contextos mais gerais, onde a exceção lançada durante o fechamento não é necessariamente uma IOException". No universo Java, ser "menos rigoroso" tem uma impressão negativa.
Manancial de