thực hiện Đóng hoặc thực hiện AutoClosizable


127

Tôi đang trong quá trình học Java và tôi không thể tìm thấy bất kỳ lời giải thích tốt nào về implements Closeablevà các implements AutoCloseablegiao diện.

Khi tôi triển khai một interface Closeable, IDE Eclipse của tôi đã tạo ra một phương thức public void close() throws IOException.

Tôi có thể đóng luồng bằng cách sử dụng pw.close();mà không cần giao diện. Nhưng, tôi không thể hiểu làm thế nào tôi có thể thực hiện close()phương thức bằng giao diện. Và, mục đích của giao diện này là gì?

Ngoài ra tôi muốn biết: làm thế nào tôi có thể kiểm tra nếu IOstreamthực sự đóng cửa?

Tôi đã sử dụng mã cơ bản dưới đây

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
Tôi nghĩ tất cả đã được nói, nhưng có lẽ bạn quan tâm đến bài viết sau đây về thử trên ressource: docs.oracle.com/javase/tutorial/essential/exceptions/ . Điều này cũng có thể hữu ích để hiểu các câu trả lời nhất định.
crusam

Câu trả lời:


40

Dường như với tôi rằng bạn không quen thuộc lắm với các giao diện. Trong mã bạn đã đăng, bạn không cần phải thực hiện AutoCloseable.

Bạn chỉ phải (hoặc nên) thực hiện Closeablehoặc AutoCloseablenếu bạn sắp thực hiện chính mình PrintWriter, nơi xử lý các tệp hoặc bất kỳ tài nguyên nào khác cần phải đóng.

Trong thực hiện của bạn, nó là đủ để gọi pw.close(). Bạn nên làm điều này trong một khối cuối cùng:

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ạn mã trên có liên quan đến Java 6. Trong Java 7, điều này có thể được thực hiện thanh lịch hơn (xem câu trả lời này ).


3
Tại sao chỉ với một PrintWriter? Đặc biệt AutoClosablecác đối tượng có thể được sử dụng trong nhiều trường hợp hơn là chỉ PrintWriter...
glglgl

3
Bạn hoàn toàn đúng. Câu hỏi là về PrintWritervì vậy tôi đã đề cập đến nó để được cụ thể hơn.
Kai

7
Tại sao mô tả tình huống cho Java 6 trong bối cảnh AutoCloseable? try-with-resourcesThay vào đó, hãy thể hiện một cách thay thế
ᴠɪɴᴄᴇɴᴛ

191

AutoCloseable(được giới thiệu trong Java 7) cho phép sử dụng thành ngữ try-with-resource :

public class MyResource implements AutoCloseable {

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

}

Bây giờ bạn có thể nói:

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

và JVM sẽ close()tự động gọi cho bạn.

Closeable là một giao diện cũ hơn. Đối với một số lý doĐể duy trì khả năng tương thích ngược, các nhà thiết kế ngôn ngữ đã quyết định tạo một cái riêng biệt. Điều này cho phép không chỉ tất cả Closeablecác lớp (như ném luồng IOException) được sử dụng trong tài nguyên thử, mà còn cho phép ném các ngoại lệ được kiểm tra tổng quát hơn từ đó close().

Khi nghi ngờ, sử dụng AutoCloseable, người dùng của lớp của bạn sẽ biết ơn.


107
Lý do rất đơn giản: Closeable.close()ném IOException. Rất nhiều close()phương pháp có thể đem lại lợi ích của thử-với-nguồn lực ném ngoại lệ kiểm tra khác (ví dụ như java.sql.Connection.close()để AutoCloseable.close()ném ExceptionThay đổi hiện có. CloseableHợp đồng sẽ phá vỡ tất cả các ứng dụng hiện có / thư viện dựa vào hợp đồng mà close()chỉ ném IOExceptionvà không phải tất cả) trường hợp ngoại lệ kiểm tra (.
Đánh dấu Rotteveel

4
@MarkRotteveel: +1, cảm ơn. Tôi đã sửa câu trả lời của mình để phản ánh đề xuất và ý kiến ​​của bạn.
Tomasz Nurkiewicz

9
Và cũng: Closeable.close()được yêu cầu là idempotent. AutoCloseable.close()là không, mặc dù nó vẫn được khuyến khích.
Lukas Eder

2
Ngoài ra, không sử dụng mặc định public void close( ) throws Exception- sử dụng một ngoại lệ cụ thể hơn nếu bạn có thể (e..g IOException)
gerardw

3
Closeablekhông đảm bảo sự bình tĩnh. Nó đòi hỏi sự bình tĩnh trong việc thực hiện close()phương pháp của người dùng. Và liệu IOExceptioncụ thể hơn / phù hợp hơn tùy thuộc vào trường hợp sử dụng.
xdhmoore

70

Closeablemở rộng AutoCloseablevà được dành riêng cho các luồng IO: nó ném IOException thay vì Exception và không có giá trị, trong khi AutoClosizable không cung cấp bảo đảm này.

Tất cả điều này được giải thích trong javadoc của cả hai giao diện.

Việc triển khai AutoClosizable (hoặc có thể đóng) cho phép một lớp được sử dụng làm tài nguyên của cấu trúc try-with-resource được giới thiệu trong Java 7, cho phép tự động đóng các tài nguyên đó ở cuối khối, mà không phải thêm khối cuối cùng đóng tài nguyên rõ ràng.

Lớp của bạn không đại diện cho một tài nguyên có thể đóng và hoàn toàn không có điểm nào trong việc triển khai giao diện này: không thể đóng IOTest. Thậm chí không thể khởi tạo nó, vì nó không có bất kỳ phương thức cá thể nào. Hãy nhớ rằng việc thực hiện một giao diện có nghĩa là có một mối quan hệ giữa lớp và giao diện. Bạn không có mối quan hệ như vậy ở đây.


5
Chỉ cần triển khai Closable cho các lớp liên quan đến luồng và AutoClosable cho các lớp khác yêu cầu tính năng tự động đóng.
lospejos

7

Đây là một ví dụ nhỏ

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

Đây là đầu ra:

GeneralTest 
From Close -  AutoCloseable  
From Final Block

Nó là tốt hơn để viết đầu ra cũng vì vậy sẽ không cần một dự án thử nghiệm cho một mã ngắn như vậy.
raxetul

Trong phương thức close (), chúng ta không cần phải đóng tài nguyên một cách rõ ràng? Có lẽ chỉ có tuyên bố in.
Shailesh Waghmare

@ShaileshWaghmare có chính xác. nhưng với mục đích thử nghiệm tôi đã đề cập đến trong snip Code.
Lova Chittumuri

@LovaChittumuri Nó sẽ giống như this.close()hoặc một cái gì đó trong mã?, Bởi vì nó được gọi tự động. (Chỉ để chắc chắn)
Shailesh Waghmare

@shailesh Waghmare Bạn có muốn kiểm tra tôi không.
Lova Chittumuri

6

Các try-with-resourcesTuyên Bố.

Đây try-with-resources statementlà một trytuyên bố tuyên bố một hoặc nhiều tài nguyên. A resourcelà một đối tượng phải được đóng lại sau khi chương trình kết thúc với nó. Việc try-with-resources statementđảm bảo rằng mỗi tài nguyên được đóng ở cuối câu lệnh. Bất kỳ đối tượng nào thực hiện java.lang.AutoCloseable, bao gồm tất cả các đối tượng thực hiện java.io.Closeable, có thể được sử dụng làm tài nguyên.

Ví dụ sau đây đọc dòng đầu tiên từ một tập tin. Nó sử dụng một thể hiện BufferedReaderđể đọc dữ liệu từ tệp. BufferedReaderlà một tài nguyên phải được đóng lại sau khi chương trình kết thúc với nó:

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

Trong ví dụ này, tài nguyên được khai báo trong câu lệnh try-with-resource là BufferedReader. Tuyên bố khai báo xuất hiện trong ngoặc đơn ngay sau từ khóa try. Lớp BufferedReader, trong Java SE 7 trở lên, thực hiện giao diện java.lang.AutoCloseable. Bởi vì BufferedReadercá thể được khai báo trong một câu lệnh try-with-resource, nó sẽ bị đóng bất kể câu lệnh try hoàn thành bình thường hay đột ngột (do kết quả của phương thức BufferedReader.readLineném một IOException).

Trước Java SE 7, bạn có thể sử dụng một finallykhối để đảm bảo rằng tài nguyên được đóng bất kể câu lệnh thử hoàn thành bình thường hay đột ngột. Ví dụ sau sử dụng một finallykhối thay vì một try-with-resourcescâu lệnh:

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

}

Vui lòng tham khảo các tài liệu .


6

Gần đây tôi đã đọc Sách hướng dẫn lập trình Java SE 8 ii.

Tôi tìm thấy một cái gì đó về sự khác biệt giữa AutoCloseablevs Closeable.

Các AutoCloseablegiao diện đã được giới thiệu trong Java 7. Trước đó, giao diện khác tồn tại được gọi là Closeable. Nó tương tự như những gì các nhà thiết kế ngôn ngữ muốn, với các ngoại lệ sau:

  • Closeablehạn chế các loại ngoại lệ ném đến IOException.
  • Closeable đòi hỏi phải thực hiện để được bình tĩnh.

Các nhà thiết kế ngôn ngữ nhấn mạnh khả năng tương thích ngược. Vì việc thay đổi giao diện hiện tại là không mong muốn, họ đã tạo một giao diện mới được gọi là AutoCloseable. Giao diện mới này ít nghiêm ngặt hơn Closeable. Kể từ khi Closeableđáp ứng các yêu cầu cho AutoCloseable, nó bắt đầu thực hiện AutoCloseablekhi cái sau được giới thiệu.


1
Thay vì nói rằng "Giao diện mới này ít nghiêm ngặt hơn Closeable", tôi khuyên bạn nên nói "Giao diện mới này có thể được sử dụng trong các bối cảnh chung hơn, trong đó ngoại lệ được ném trong khi đóng không nhất thiết phải là IOException". Trong vũ trụ Java, việc "ít nghiêm ngặt hơn" có một sự rung cảm tiêu cực về nó.
fountainhead
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.