mengimplementasikan Closeable atau mengimplementasikan AutoCloseable

128

Saya dalam proses belajar Java dan saya tidak dapat menemukan penjelasan yang baik di implements Closeabledan implements AutoCloseableinterface.

Saat saya mengimplementasikan interface Closeable, Eclipse IDE saya membuat metode public void close() throws IOException.

Saya dapat menutup aliran menggunakan pw.close();tanpa antarmuka. Tetapi, saya tidak dapat memahami bagaimana saya dapat mengimplementasikan close()metode menggunakan antarmuka. Dan, apa tujuan dari antarmuka ini?

Saya juga ingin tahu: bagaimana cara memeriksa apakah IOstreambenar-benar tutup?

Saya menggunakan kode dasar di bawah ini

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
sumber
2
Saya pikir semua telah dikatakan, tapi mungkin Anda tertarik dengan artikel berikut tentang mencoba ressources: docs.oracle.com/javase/tutorial/essential/exceptions/… . Ini mungkin juga membantu untuk memahami jawaban yang diberikan.
crusam

Jawaban:

40

Menurut saya, Anda tidak terlalu akrab dengan antarmuka. Dalam kode yang telah Anda posting, Anda tidak perlu menerapkannya AutoCloseable.

Anda hanya perlu (atau harus) mengimplementasikan Closeableatau AutoCloseablejika Anda akan mengimplementasikannya sendiri PrintWriter, yang menangani file atau resource lain yang perlu ditutup.

Dalam implementasi Anda, cukup dengan memanggil pw.close(). Anda harus melakukan ini di blok terakhir:

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

Kode di atas terkait dengan Java 6. Di Java 7 ini bisa dilakukan dengan lebih elegan (lihat jawaban ini ).

Kai
sumber
3
Kenapa hanya dengan a PrintWriter? Terutama AutoClosableobjek dapat digunakan dalam lebih banyak keadaan daripada hanya PrintWriters ...
glglgl
3
Anda benar sekali. Pertanyaannya adalah tentang PrintWriterjadi saya sebutkan untuk lebih spesifik.
Kai
7
Mengapa menggambarkan situasi untuk Jawa 6 dalam konteks AutoCloseable? Lebih baik tunjukkan try-with-resourcessaja…
ᴠɪɴᴄᴇɴᴛ
191

AutoCloseable(diperkenalkan di Java 7) memungkinkan penggunaan idiom try-with-resources :

public class MyResource implements AutoCloseable {

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

}

Sekarang Anda dapat mengatakan:

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

dan JVM akan menelepon close()secara otomatis untuk Anda.

Closeable adalah antarmuka yang lebih lama. Untuk beberapa alasanUntuk menjaga kompatibilitas ke belakang, desainer bahasa memutuskan untuk membuat yang terpisah. Hal ini memungkinkan tidak hanya semua Closeablekelas (seperti pelemparan aliran IOException) untuk digunakan dalam percobaan dengan sumber daya, tetapi juga memungkinkan pelemparan pengecualian yang dicentang yang lebih umum dari close().

Jika ragu, gunakan AutoCloseable, pengguna kelas Anda akan berterima kasih.

Tomasz Nurkiewicz
sumber
107
Alasannya sederhana: Closeable.close()lemparan IOException. Banyak close()metode yang bisa menguntungkan dari try-dengan-sumber membuang pengecualian diperiksa lainnya (misalnya java.sql.Connection.close()jadi AutoCloseable.close()melempar ExceptionMengubah ada. CloseableKontrak akan memecahkan semua aplikasi yang ada / perpustakaan mengandalkan kontrak yang close()hanya melempar IOExceptiondan tidak semua (diperiksa) pengecualian.
Mark Rotteveel
4
@MarkRotteveel: +1, terima kasih. Saya mengoreksi jawaban saya untuk mencerminkan saran dan komentar Anda.
Tomasz Nurkiewicz
9
Dan juga: Closeable.close()dituntut untuk menjadi idempoten. AutoCloseable.close()tidak, meski masih sangat disarankan.
Lukas Eder
2
Juga, jangan gunakan default public void close( ) throws Exception- gunakan pengecualian yang lebih spesifik jika Anda bisa (misalnya IOException)
gerardw
3
Closeabletidak menjamin idempotensi. Ini membutuhkan idempotensi dalam implementasi close()metode oleh pengguna. Dan apakah IOExceptionlebih spesifik / sesuai tergantung pada kasus penggunaan.
xdhmoore
71

Closeablemeluas AutoCloseable, dan secara khusus didedikasikan untuk aliran IO: ini melontarkan IOException dan bukan Exception, dan idempoten, sedangkan AutoCloseable tidak memberikan jaminan ini.

Ini semua dijelaskan di javadoc dari kedua antarmuka.

Menerapkan AutoCloseable (atau Closeable) memungkinkan kelas untuk digunakan sebagai sumber daya dari konstruksi coba-dengan-sumber daya yang diperkenalkan di Java 7, yang memungkinkan penutupan sumber daya tersebut secara otomatis di akhir blok, tanpa harus menambahkan blok akhirnya yang menutup sumber daya secara eksplisit.

Kelas Anda tidak mewakili sumber daya yang bisa ditutup, dan sama sekali tidak ada gunanya mengimplementasikan antarmuka ini: IOTest tidak bisa ditutup. Seharusnya tidak mungkin untuk membuat instance, karena tidak memiliki metode instance apa pun. Ingatlah bahwa mengimplementasikan antarmuka berarti ada hubungan is-a antara kelas dan antarmuka. Anda tidak memiliki hubungan seperti itu di sini.

JB Nizet
sumber
5
Cukup terapkan Closable untuk kelas yang terkait dengan aliran, dan AutoClosable untuk kelas lain yang memerlukan fitur tutup otomatis.
lospejos
7

Inilah contoh kecilnya

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

Inilah hasilnya:

GeneralTest 
From Close -  AutoCloseable  
From Final Block
Lova Chittumuri
sumber
Lebih baik menulis hasilnya juga sehingga tidak perlu proyek percobaan untuk kode sesingkat itu.
raxetul
Dalam metode close (), bukankah kita perlu menutup sumber daya secara eksplisit? Mungkin hanya ada pernyataan cetak.
Shailesh Waghmare
@Shaileshaghmare ya persis. tetapi untuk tujuan pengujian saya telah menyebutkan dalam kode snip.
Lova Chittumuri
@LovaChittumuri Jadi apakah akan seperti this.close()atau sesuatu dalam kode ?, karena dipanggil secara otomatis. (Hanya untuk memastikan)
Shailesh Waghmare
@shailesh Waghmare Apakah Anda ingin menguji saya.
Lova Chittumuri
6

The try-with-resourcesPernyataan.

Ini try-with-resources statementadalah trypernyataan yang mendeklarasikan satu atau lebih resource. A resourceadalah objek yang harus ditutup setelah program selesai dengannya. The try-with-resources statementmemastikan bahwa setiap sumber daya ditutup pada akhir pernyataan tersebut. Objek apa pun yang diimplementasikan java.lang.AutoCloseable, yang menyertakan semua objek yang diimplementasikan java.io.Closeable, dapat digunakan sebagai sumber daya.

Contoh berikut membaca baris pertama dari sebuah file. Ini menggunakan contoh BufferedReaderuntuk membaca data dari file. BufferedReaderadalah sumber daya yang harus ditutup setelah program selesai dengannya:

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

Dalam contoh ini, sumber daya yang dideklarasikan dalam pernyataan coba-dengan-sumber daya adalah BufferedReader. Pernyataan deklarasi muncul dalam tanda kurung segera setelah kata kunci coba. Kelas BufferedReader, di Java SE 7 dan yang lebih baru, mengimplementasikan antarmuka java.lang.AutoCloseable. Karena BufferedReaderinstance dideklarasikan dalam pernyataan try-with-resource, itu akan ditutup terlepas dari apakah pernyataan try selesai secara normal atau tiba-tiba (sebagai hasil dari metode yang BufferedReader.readLinedilemparkan IOException).

Sebelum Java SE 7, Anda dapat menggunakan finallyblok untuk memastikan bahwa sumber daya ditutup terlepas dari apakah pernyataan try selesai secara normal atau tiba-tiba. Contoh berikut menggunakan finallyblok, bukan try-with-resourcespernyataan:

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

}

Silakan merujuk ke dokumen .

inder
sumber
6

Baru-baru ini saya telah membaca Buku Panduan Programmer Java SE 8 ii.

Saya menemukan sesuatu tentang perbedaan antara AutoCloseablevs Closeable.

The AutoCloseableantarmuka diperkenalkan di Jawa 7. Sebelum itu, antarmuka lain ada yang disebut Closeable. Itu mirip dengan apa yang diinginkan oleh desainer bahasa, dengan pengecualian berikut:

  • Closeablemembatasi jenis pengecualian yang diberikan IOException.
  • Closeable membutuhkan implementasi untuk menjadi idempoten.

Para desainer bahasa menekankan kompatibilitas ke belakang. Karena mengubah antarmuka yang ada tidak diinginkan, mereka membuat antarmuka baru yang disebut AutoCloseable. Antarmuka baru ini tidak seketat Closeable. Karena Closeablememenuhi persyaratan AutoCloseable, itu mulai diterapkan AutoCloseableketika yang terakhir diperkenalkan.

Arvind Katte
sumber
1
Alih-alih mengatakan bahwa "Antarmuka baru ini kurang ketat dari Closeable", saya sarankan untuk mengatakan "Antarmuka baru ini dapat digunakan dalam konteks yang lebih umum, di mana pengecualian yang dilemparkan selama penutupan belum tentu merupakan IOException". Di alam semesta Jawa, menjadi "kurang ketat" memiliki kesan negatif tentangnya.
Fountainhead