2012-06-29 40 views
21

Tôi có sau đoạn mã trong một khối try/catchinputstreams Bế mạc trong Java

InputStream inputstream = conn.getInputStream(); 
InputStreamReader inputstreamreader = new InputStreamReader(inputstream); 
BufferedReader bufferedreader = new BufferedReader(inputstreamreader); 

Câu hỏi của tôi là khi tôi phải đóng những con suối trong khối finally, tôi có phải đóng tất cả các 3 luồng hoặc chỉ đóng befferedreader sẽ đóng tất cả các luồng khác?

+1

Bản sao có thể có của [Tôi có cần đóng() cả FileReader và BufferedReader không?] (Http://stackoverflow.com/questions/1388602/do-i-need-to-close-both-filereader-and-bufferedreader) – River

Trả lời

24

Theo quy ước, các luồng bao bọc (bọc các luồng hiện có) đóng luồng cơ bản khi chúng được đóng lại, vì vậy chỉ phải đóng bufferedreader trong ví dụ của bạn. Ngoài ra, thường không có hại để đóng một luồng đã đóng, vì vậy việc đóng tất cả 3 luồng sẽ không bị tổn thương.

+0

Bạn không thể đảm bảo rằng việc triển khai luồng sẽ không ném ngoại lệ khi đóng nó nếu nó đã đóng. Vì vậy, nó là cách tốt hơn để dính vào cách thích hợp và đóng chỉ BufferedReader – Soronthar

+1

@Soronthar Sau đó, thực hiện dòng này không hợp lệ bởi hợp đồng mà nói 'Nếu dòng đã được đóng cửa sau đó gọi phương pháp này không có hiệu lực.' Tất cả các thực hiện hợp lệ PHẢI cư xử như thế này Nó hoàn toàn hợp pháp (và phổ biến) để đóng một luồng đã đóng. Thông thường bạn đóng nó lần đầu tiên trong try-block và lần thứ hai trong khối cuối cùng, nơi đóng trong try-block cho bạn cơ hội phản ứng ngoại lệ và đóng trong khối cuối cùng là để đảm bảo đóng. –

+0

@ FabianBarney bạn nói đúng, tôi quên họ đã trang bị thêm các luồng với giao diện Có thể đóng trong JSE 6. – Soronthar

0

Theo quy tắc chung, bạn nên đóng mọi thứ theo thứ tự ngược lại mà bạn đã mở chúng.

0

Tôi sẽ đóng tất cả chúng theo thứ tự ngược mà bạn đã mở chúng, như thể khi mở chúng sẽ đẩy người đọc đến một ngăn xếp và đóng sẽ bật trình đọc từ ngăn xếp.

Cuối cùng, sau khi đóng tất cả, "ngăn xếp trình đọc" phải trống.

+0

Lý do của bạn cho đề xuất này là gì? Khi luồng đầu vào được lọc và trình đọc được chỉ định để đóng luồng lồng nhau trên close()? – EJP

+0

Cảm giác thông thường, tôi đoán vậy. Có câu trả lời tốt hơn trong chủ đề này, như các phiếu bầu cho thấy. Một số thậm chí còn hiển thị mã nguồn cho thư viện. –

3

Đóng nắp ngoài cùng là đủ (ví dụ: BufferedReader). Đọc source code of BufferedReader chúng ta có thể thấy rằng nó đóng cửa khu vực nội Reader khi phương pháp thân của mình được gọi là:

513  public void close() throws IOException { 
514   synchronized (lock) { 
515    if (in == null) 
516     return; 
517    in.close(); 
518    in = null; 
519    cb = null; 
520   } 
521  } 
522 } 
0

Bạn chỉ cần phải đóng tài nguyên thực tế. Bạn nên đóng tài nguyên ngay cả khi việc xây dựng trang trí không thành công. Đối với đầu ra, bạn nên tuôn ra đối tượng trang trí nhất trong trường hợp hạnh phúc.

Một số biến chứng:

  • Đôi khi trang trí là những tài nguyên khác nhau (một số triển khai nén sử dụng heap C).
  • Đóng trang trí trong trường hợp buồn thực sự gây ra tuôn ra, với sự nhầm lẫn tiếp theo như không thực sự đóng tài nguyên cơ bản.
  • Có vẻ như tài nguyên cơ bản của bạn là URLConnection, không có phương thức disconnect/close như vậy.

Bạn có thể cân nhắc việc sử dụng thành phần Thực thi xung quanh để bạn không phải nhân đôi loại điều này.

4

Thông thường, bạn chỉ cần đóng luồng ngoài cùng nhiều nhất, vì theo quy ước, nó phải kích hoạt gần trên các luồng cơ bản.

Vì vậy, thường mã trông như thế này:

BufferedReader in = null; 

try { 
    in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
    ... 
    in.close(); // when you care about Exception-Handling in case when closing fails 
} 
finally { 
    IOUtils.closeQuietly(in); // ensure closing; Apache Commons IO 
} 

Tuy nhiên có thể có trường hợp hiếm gặp nơi một constructor dòng cơ bản đặt ra một ngoại lệ nơi con suối đã được mở ra. Trong trường hợp đó mã trên sẽ không đóng luồng cơ bản vì hàm tạo bên ngoài chưa bao giờ được gọi và in là rỗng. Vì vậy, khối cuối cùng không đóng bất cứ điều gì để lại dòng cơ bản mở ra.

Kể từ Java 7 bạn có thể làm điều này:

try (OutputStream out1 = new ...; OutputStream out2 = new ...) { 
     ... 
     out1.close(); //if you want Exceptions-Handling; otherwise skip this 
     out2.close(); //if you want Exceptions-Handling; otherwise skip this    
    } // out1 and out2 are auto-closed when leaving this block 

Trong hầu hết các trường hợp, bạn không muốn xử lý ngoại lệ khi được nuôi trong khi đóng cửa nên bỏ qua những đóng rõ ràng() gọi.

Chỉnh sửa Đây là một số mã dành cho những người không phải là tín hữu khi sử dụng mô hình này. Bạn cũng có thể muốn đọc Apache Commons IOUtils javadoc về phương pháp closeQuietly().

OutputStream out1 = null; 
    OutputStream out2 = null; 

    try { 
     out1 = new ...; 
     out2 = new ...; 

     ... 

     out1.close(); // can be skipped if we do not care about exception-handling while closing 
     out2.close(); // can be skipped if we ... 
    } 
    finally { 
     /* 
     * I've some custom methods in my projects overloading these 
     * closeQuietly() methods with a 2nd param taking a logger instance, 
     * because usually I do not want to react on Exceptions during close 
     * but want to see it in the logs when it happened. 
     */ 
     IOUtils.closeQuietly(out1); 
     IOUtils.closeQuietly(out2); 
    } 

Sử dụng @ "lời khuyên" của Tom sẽ rời out1 mở ra khi tạo ra các out2 đặt ra một ngoại lệ. Lời khuyên này là từ một người nào đó nói về It's a continual source of errors for obvious reasons. Vâng, tôi có thể bị mù, nhưng điều đó không rõ ràng đối với tôi. Mô hình của tôi là an toàn ngốc nghếch trong mọi trường hợp sử dụng mà tôi có thể nghĩ đến trong khi mẫu của Tom dễ bị lỗi.

+0

Xin đừng làm như vậy nhảy 'null'. Đó là một nguồn liên tục của các lỗi vì lý do rõ ràng. Và những gì một mớ hỗn độn. –

+1

Đây là kiểu bình thường. Bạn còn muốn làm gì nữa? –

+0

'obtain(); thử {use(); } cuối cùng {release(); } ' –

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