Câu hỏi Tôi có đang sử dụng tài nguyên thử nghiệm Java 7 chính xác không


Tôi hy vọng người đọc đã đọc và trình đọc tệp đóng và các tài nguyên được phát hành nếu ngoại lệ bị ném.

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
    {
        return read(br);
    } 
}

Tuy nhiên, có một yêu cầu để có một catch khoản để đóng thành công?

CHỈNH SỬA:

Về cơ bản, là mã trên trong Java 7 tương đương với dưới đây cho Java 6:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{

    BufferedReader br = null;

    try
    {
        br = new BufferedReader(new FileReader(filePath));

        return read(br);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        try
        {
            if (br != null) br.close();
        }
        catch(Exception ex)
        {
        }
    }

    return null;
}

76
2017-07-15 09:32


gốc


Sau khi đọc câu hỏi của bạn một lần nữa, tôi không chắc chắn nếu tôi hiểu nó tốt. Bạn có thể giải thích nó không? - Maroun
Chào. Cheetah, tôi đang cố gắng hiểu vai trò của người đầu tiên catch ví dụ của bạn cho Java 6. I.e. catch (Exception ex) { throw ex; } - nó chỉ là ném lại ngoại lệ, nó không làm gì cả, nó có thể dễ dàng bị loại bỏ mà không bị tổn thương. Hay tôi đang thiếu một cái gì đó? - Sasha
Không có gì sai về cú pháp của bạn. Nếu bạn muốn biết thêm về thử-với-tài nguyên, hãy kiểm tra bài viết này: Java thử với các nguồn lực - Hussein Terek


Các câu trả lời:


Đó là chính xác và không có yêu cầu catch mệnh đề. Oracle java 7 doc nói rằng tài nguyên sẽ bị đóng bất kể liệu một ngoại lệ có thực sự bị ném hay không.

Bạn nên sử dụng catch mệnh đề chỉ khi bạn muốn phản ứng khi ngoại lệ. Các catch mệnh đề sẽ được thực hiện sau tài nguyên đã bị đóng.

Đây là một đoạn trích từ Hướng dẫn của Oracle:

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

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
} // In this example, the resource declared in the try-with-resources statement is a BufferedReader.

... Bởi vì thể hiện BufferedReader đượ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 thử hoàn thành bình thường hoặc đột ngột (do kết quả của   phương thức BufferedReader.readLine ném một IOException).

CHỈNH SỬA

Về câu hỏi được chỉnh sửa mới:

Mã trong Java 6 thực thi catch và sau đó finally khối. Điều này khiến tài nguyên vẫn có khả năng mở trong catch khối.

Trong cú pháp Java 7, các tài nguyên được đóng lại trước các catch chặn, vì vậy tài nguyên đã bị đóng trong catch thực thi khối. Đây là tài liệu trong liên kết ở trên:

Trong một câu lệnh try-with-resources, bất kỳ khối catch hoặc finally nào đều được chạy   sau khi các tài nguyên được khai báo đã bị đóng.


94
2017-07-15 09:40





Việc bạn sử dụng các tài nguyên thử nghiệm sẽ hoạt động tốt trong trường hợp cụ thể này, nhưng nó không hoàn toàn chính xác nói chung. Bạn không nên chuỗi các nguồn tài nguyên như vậy bởi vì nó có thể dẫn đến những bất ngờ khó chịu. Giả sử bạn có kích thước bộ đệm biến:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (BufferedReader br = new BufferedReader(new FileReader(filePath), sz))
    {
        return read(br);
    } 
}

Giả sử có điều gì đó sai và bạn đã kết thúc với sz tiêu cực. Trong trường hợp này, tài nguyên tệp của bạn (được tạo qua new FileReader(filePath)) sẽ KHÔNG PHẢI được đóng lại.

Để tránh vấn đề này, bạn nên chỉ định từng tài nguyên riêng biệt như sau:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (FileReader file = new FileReader(filePath);
         BufferedReader br = new BufferedReader(file, sz))
    {
        return read(br);
    } 
}

Trong trường hợp này ngay cả khi khởi tạo br thất bại file vẫn bị đóng. Bạn có thể tìm thêm chi tiết đây và đây.


65
2018-01-25 09:37



Tôi đang cố gắng hiểu tại sao tài nguyên được tạo qua new FileReader(filePath)) sẽ không đóng trong trường hợp IllegalArgumentException được ném khi sz là âm. Không phải là cố gắng với các nguồn lực đóng tất cả các AutoClosable tài nguyên không phân biệt bất kỳ ngoại lệ nào được ném ra? - Prasoon Joshi
@ PrasoonJoshi Không, nó chỉ gọi .close() cho các biến đã được khai báo trong bộ khởi tạo try-with-resources. Đó là lý do tại sao tách nó thành hai tờ khai trong ví dụ này làm các trick. - Mario Carneiro
Andrii và @Mario Bạn vừa đúng vừa sai. Trong ví dụ đầu tiên, FileReader không được đóng bởi logic thử-với-tài nguyên. Nhưng khi BufferedReader được đóng, nó cũng sẽ đóng gói FileReader. Để có bằng chứng, hãy xem nguồn java.io.BufferedReader.close (). Kết quả là, mã từ ví dụ đầu tiên nên được ưu tiên hơn vì nó ngắn gọn hơn. - jschreiner
@jschreiner Đúng, mặc dù vấn đề của Andrii (phần nào có tính cạnh tranh) trong đó sz < 0 gây ra các nhà xây dựng để ném một ngoại lệ trên thực tế sẽ khiến cho tài nguyên bị rò rỉ. - Mario Carneiro
@mario Tôi đồng ý. Các nhà xây dựng bên ngoài có thể thất bại, và các nguồn lực bên trong sẽ bị rò rỉ. Tôi không thấy điều đó trước đây, cảm ơn bạn. - jschreiner