2009-07-22 26 views
17

Cập nhật: Khi @PaulGroke chỉ ra bên dưới, mọi thứ đã thay đổi với Java 7: hiện tại có AutoCloseable. Không được gắn với luồng và được hỗ trợ bởi cấu trúc try-with-resources mới.Nên có thể sử dụng được như là tương đương Java cho .NET's IDisposable?

AutoCloseable là tương đương Java trực tiếp cho giao diện IDisposable của .NET.


Giao diện Closeable giới thiệu trong Java 1.5 gắn liền chặt chẽ với suối, và thậm chí còn có một ngoại lệ cho specifier IOException. Điều này cho thấy rằng nó chỉ nên được sử dụng cho các luồng hoặc các hoạt động liên quan đến IO khác, thay vì logic dọn dẹp mục đích chung.

Chắc chắn mô tả cho phương pháp close() sẽ làm cho hoàn toàn không có cảm giác bên ngoài của một bối cảnh dòng/IO:

void close() throws IOException

Đóng dòng này và phiên bản bất kỳ tài nguyên hệ thống liên kết với nó.

Tôi có nên do đó tuyên bố giao diện của riêng tôi, Disposable, với một phương pháp Dispose() vào nó, và sử dụng như một chất tương tự với giao diện IDisposable NET không? Hoặc tôi có nên sử dụng lại Closeable mặc dù nó có thể không hoàn toàn phù hợp không?

+1

@Pharap Có hai mẫu riêng biệt để triển khai 'IDisposable' được đề cập trên trang bạn liên kết tới. Việc triển khai 'Object.Finalize()' chỉ được yêu cầu trong kịch bản tương đối hiếm hoi mà đối tượng của bạn chịu trách nhiệm trực tiếp về phân bổ tài nguyên không được quản lý (tức là tài nguyên gốc không được bao bọc với SafeHandle). Câu lệnh của bạn rằng "cách đề xuất của .NET để thực hiện' IDisposable' [...] yêu cầu sử dụng 'Object.Finalize()' "không hoàn toàn chính xác. –

Trả lời

11

Đặc biệt là khi đóng() ném một IOException thì bạn phải viết mã xử lý ngoại lệ cho, tôi khuyên bạn nên viết giao diện của riêng bạn. Giao diện này sau đó có thể ném bất kỳ ngoại lệ đã kiểm tra nào phù hợp với việc sử dụng mà bạn muốn đặt giao diện.

Giao diện có xu hướng biểu thị ý định trong tâm trí của người đọc, do đó, việc có một lớp thực hiện giao diện có thể kết nối với IO sẽ khiến người đọc giả định rằng lớp cũng dựa trên IO.

Rõ ràng, nếu các đối tượng bạn muốn đóng tất cả liên quan đến IO, bạn nên sử dụng Có thể đóng. Nhưng nếu không, hãy truy cập

/** Interface for objects that require cleanup post-use. Call dispose() in finally block! */ 
public interface Disposable { 
    public void dispose(); 
} 
34

Tôi chắc chắn hầu hết mọi người đều biết điều đó, nhưng vì câu hỏi này vẫn nằm trong số các kết quả hàng đầu khi tìm kiếm "IDisposable Java" (kết quả # 2 cho tôi vừa rồi) và nó vẫn chưa được đề cập ở đây ...

Mọi thứ đã thay đổi với Java 7: hiện tại có AutoCloseable. Không được gắn với luồng và được hỗ trợ bởi cấu trúc try-with-resources mới.

+0

Trong khi tôi thấy khó chịu rằng Java mất nhiều thời gian để có được tương đương với 'IDisposable', và tôi coi việc thiếu một cấu trúc như một lỗ hổng quan trọng trong Java, tôi tán dương những người sáng tạo Java để nhận ra sự cần thiết cho phép cả hai các trường hợp ngoại lệ và các biểu thức dọn dẹp khối try-block được truyền bá lên ngăn xếp cuộc gọi. Sở thích của tôi sẽ là có 'try-with-resources' bọc bất kỳ trường hợp ngoại lệ nào xảy ra trong khối dọn dẹp trong một' CleanupFailedException' (sẽ cho biết ngoại lệ nào - nếu có - xảy ra trong khối 'try', cùng với một danh sách các ngoại lệ dọn dẹp) ... – supercat

+0

... và cũng cung cấp một phương tiện mà mã dọn dẹp có thể cho biết khối 'try' đã thành công hay thất bại (ví dụ, nếu một ngoại lệ được ném bởi mã đang sửa đổi một cái gì đó được bảo vệ bởi một khóa, khóa thường không được phát hành và không được giữ vô thời hạn, nhưng thay vào đó sẽ bị vô hiệu hóa để bất kỳ nỗ lực nào trong tương lai hoặc chờ lấy khóa sẽ ném ngay 'badLockExitException'; -resources construct có thể cho phép một đối tượng khóa thực hiện các ngữ nghĩa đó một cách tự động). – supercat

+1

Tôi có xu hướng đồng ý, mặc dù lý do là khả năng tương thích ngược để cho phép [Có thể đóng được] (http://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) để mở rộng [AutoCloseable] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html). Một điều cần xem xét là nếu một ngoại lệ được ném vào cơ thể và dọn dẹp cũng ném một ngoại lệ các ngoại lệ sôi nổi [getSuppressed] (http://docs.oracle.com/javase/8/docs/api/java/lang/ Throwable.html # getSuppressed--) chứa ngoại lệ từ [close()] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html#close--). –

1

Khi thực hiện Closeable (hoặc AutoClosable cho rằng vấn đề) trong một lớp học nó cũng có thể chỉ cần bỏ qua ném khai:

class X implements Closeable { 
    @Override public void close() /* I don't throw */ { 

    } 
} 

Vì vậy, khi một người nào đó đang sử dụng một đối tượng đánh máy họ có thể gọi close() mà không cần phải bắt bất cứ điều gì:

void f() { // notice no need for throws because close() doesn't throw 
    X x = new X(); 
    try { 
     // do something 
    } finally { 
     x.close(); 
    } 
} 

Nó cũng tương thích với bất cứ điều gì mong đợi một Closeable: nếu đối tượng này được thông qua vào đâu đó để xử lý Closeable, họ đã dự đoán một ngoại lệ và xử lý nó một cách chính xác, mặc dù trong trường hợp này là vô ích.

này bao gồm các thư viện như Guava Closeables và Java 7 try-với-các nguồn lực như Paul Groke gợi ý:

try (X x = new X()) { 
    // do something 
} 

Có một caveat hiếm mặc dù: bạn không thể giới thiệu lại các ngoại lệ trong trẻ em lớp một lần nó bị tước:

class Y extends X { 
            /* compile error */ 
    @Override public void close() throws IOException { 
     // Y.close clashes with X.close: overridden method does not throw IOException 
    } 
} 
Các vấn đề liên quan