2009-10-05 30 views
10

Có InputStreams và OutputStreams trong Java close() khi hủy không? Tôi hoàn toàn hiểu rằng đây có thể là hình thức xấu (đặc biệt trong thế giới C và C++), nhưng tôi tò mò.Đầu vào/OutputStream có bị đóng không?

Ngoài ra, giả sử tôi có đoạn mã sau:

private void foo() 
{ 
    final string file = "bar.txt"; 
    Properties p = new Properties(); 
    p.load(new FileInputStream(file)); 
    //... 
} 

Liệu các FileInputStream không tên đi ra khỏi phạm vi sau p.load(), và do đó bị phá hủy, kinda giống như quy tắc Phạm vi C++? Tôi đã cố gắng tìm kiếm phạm vi biến vô danh cho java trên Google, nhưng điều đó đã không bật lên những gì tôi nghĩ rằng nó sẽ được.

Cảm ơn.

+0

Cảm ơn tất cả vì sự giúp đỡ! – Calyth

+0

Lưu ý rằng 'try' với các tài nguyên trong Java 7 hoặc cao hơn sẽ làm cho vấn đề này trở thành một hoạt động tương đối đơn giản (chỉ yêu cầu một phép gán biến bổ sung và dĩ nhiên là' try' chính nó). Cũng lưu ý rằng mã trên sẽ tạo ra một cảnh báo (về sự thiếu đóng) trong môi trường Eclipse của tôi. –

Trả lời

16

Câu trả lời đầu tiên: không có thứ như "hủy diệt" (theo nghĩa C++) trong Java. Chỉ có Garbage Collector, có thể hoặc không thể thức dậy và thực hiện công việc của nó khi nó thấy một vật thể sẵn sàng để thu thập. GC trong Java nói chung là không đáng tin cậy.

Câu trả lời thứ hai: đôi khi có, đôi khi không, nhưng không đáng để mạo hiểm. Từ Elliote Rusty Harold's Java IO:

Không phải tất cả các dòng cần phải được đóng — suối đầu ra mảng byte không cần phải được đóng lại, ví dụ. Tuy nhiên, các luồng được liên kết với các tệp và các kết nối mạng phải luôn được đóng khi bạn hoàn tất. Ví dụ: nếu bạn mở một tệp để viết và bỏ bê khi đóng tệp khi bạn thực hiện, thì các quy trình khác có thể bị chặn đọc hoặc ghi vào tệp đó.

Theo Harold, điều tương tự cũng xảy ra đối với luồng đầu vào hoặc đầu ra. Có một số ngoại lệ (ông ghi chú System.in), nhưng nói chung, bạn đang mạo hiểm nếu bạn không đóng các luồng tệp khi bạn hoàn tất. Và đóng chúng trong một khối cuối cùng, để đảm bảo rằng chúng đóng cửa ngay cả khi một ngoại lệ được ném ra.

5

Không, không có destructors nào trong Java. Có thể có các tham chiếu khác cho đối tượng, ngay cả sau khi một tham chiếu cụ thể đến nó nằm ngoài phạm vi (hoặc được sửa đổi). Nếu đối tượng không thể truy cập được nữa, luồng có thể có trình kết thúc của nó được gọi là đôi khi sau đó sẽ đóng luồng.

Properties.load là điều đặc biệt trong đó đóng luồng được truyền tới nó. Chỉnh sửa: Properties.loadFromXML là phương pháp đặc biệt mà tôi có vẻ đã nghĩ đến cách đây khoảng năm năm. (API doc có lẽ nên nói trước chứ không phải sau.) Cảm ơn bạn @tzimnoch.

+0

Không có destructors, nhưng có finalizers. Và finalizers cho phần lớn các lớp InputStream/OuputStream từ java.io DO đóng luồng. – ChssPly76

+5

@ ChssPly76: Đúng, nhưng không có sự bảo đảm nào * về thời điểm, hoặc thậm chí là, finalizers sẽ được gọi. Không ai. –

+1

https://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load(java.io.InputStream) "Luồng được chỉ định vẫn mở sau khi phương thức này trả về." – tzimnoch

3

Biến số vượt quá phạm vi và do đó bị phá hủy. Nhưng trong Java, có sự khác biệt rất lớn giữa biến số và đối tượng mà biến số trỏ đến.

Đối tượng được trỏ đến không bị hủy chỉ khi biến số vượt quá phạm vi. Đối tượng này chỉ bị phá hủy khi công cụ chạy Java quyết định rằng nó giống như nhận được xung quanh để phá hủy các đối tượng không được trỏ đến bởi bất kỳ biến trong phạm vi nào.

6

Tôi đã sử dụng để giả định luồng sẽ tự động bị đóng sau khi thu thập rác, nhưng bằng chứng giai thoại cho thấy rằng không tự đóng chúng dẫn đến rò rỉ tài nguyên. Bạn sẽ muốn làm một cái gì đó giống như thay vì điều này:

InputStream stream = null; 

try { 
    stream = new FileInputStream("bar.txt"); 
    Properties p = new Properties(); 
    p.load(stream); 
} 
catch(Exception e) { 
    // error handling 
} 
finally { 
    closeQuietly(stream); 
} 

closeQuietly() là một phương pháp trên IOUtils trong thư viện commons-io của Apache.

3

Câu trả lời ngắn gọn là "có thể, nhưng không đặt cược vào nó!".

Một nơi nào đó trong nhóm các lớp triển khai FileInputStream là lớp có số finalizer sẽ đóng luồng hiệu quả (và giải phóng tài nguyên) khi nó được chạy.

Vấn đề là không có gì đảm bảo rằng trình kết thúc sẽ chạy. Trích dẫn từ JLS (phần 12,6):

Các ngôn ngữ lập trình Java không chỉ định cách sớm một finalizer sẽ gọi, ngoại trừ việc nói rằng nó sẽ xảy ra trước khi lưu trữ cho các đối tượng được tái sử dụng.

Điều này làm cho quyết toán dòng có vấn đề:

  1. Nếu đối tượng Suối bạn không bao giờ trở thành rác, nó sẽ không bao giờ được hoàn thành.
  2. Nếu đối tượng Luồng của bạn được thuê, có thể mất một thời gian dài trước khi nó được thu thập và hoàn thành rác.
  3. JVM có thể cần thực hiện thêm chu kỳ GC sau khi đối tượng được xác định là không thể truy cập được trước khi trình kết thúc được thực hiện. Điều này chắc chắn được cho phép bởi JLS!
  4. Về mặt kỹ thuật, JVM không bao giờ thực thi finalizers, miễn là nó không bao giờ sử dụng lại các đối tượng với finalizers. (Tôi không biết về bất kỳ JVM chất lượng sản xuất nào có dòng này, nhưng bạn không bao giờ biết ...)
+0

Tôi nghĩ rằng nếu JVM có ít tài nguyên, nó sẽ hoàn thành các đối tượng tệp đã đóng. (Không phải để tha thứ không làm sạch sau khi chính mình.) –

+0

Bạn có thể nghĩ rằng ... nhưng AFAIK, chạy ra khỏi mô tả tập tin không kích hoạt một GC chạy mà có thể phát hiện rằng các đối tượng dòng khác là (giả thuyết) bây giờ finalizable. –

+0

@mike jones: không, không phải vậy. Điều này có thể được chứng minh thực tế. Việc thiếu bộ nhớ có thể kích hoạt bộ sưu tập rác (thậm chí còn được yêu cầu phải cố gắng hết sức trước khi ném một 'OutOfMemoryError'), nhưng gc là * không * giống hệt với việc hoàn thành. Việc thu gom rác thải sẽ khiến các đối tượng với finalizers được * enqueued * để hoàn thành sau này, nhưng nó hoàn toàn không xác định khi hoàn thành sẽ xảy ra.Vì vậy, trong khi chạy ra khỏi mô tả tập tin (hoặc bất kỳ tài nguyên không nhớ khác) không kích hoạt gc anyway (như Stephen đã chỉ ra), ngay cả khi gc được kích hoạt, nó không buộc hoàn thành. – Holger

Các vấn đề liên quan