Trong hướng dẫn này, chúng ta sẽ tìm hiểu về câu lệnh try-with-resources để đóng tài nguyên tự động.

Câu lệnh try-with-resources tự động đóng tất cả các tài nguyên ở cuối câu lệnh. Tài nguyên là một đối tượng được đóng ở cuối chương trình.

Cú pháp của nó là:

try (resource declaration) {
  // use of the resource
} catch (ExceptionType e1) {
  // catch block
}

Như đã thấy từ cú pháp trên, chúng ta khai báo câu lệnh bằng try-with-resources,

  1. khai báo và khởi tạo tài nguyên trong mệnh đề try.
  2. chỉ định và xử lý tất cả các ngoại lệ có thể được ném ra khi đóng tài nguyên.

Lưu ý: Câu lệnh try-with-resources đóng tất cả các tài nguyên triển khai interface AutoClosable .

Hãy để chúng ta lấy một ví dụ thực hiện câu lệnh try-with-resources.

Ví dụ 1: try tài nguyên

import java.io.*;

class Main {
  public static void main(String[] args) {
    String line;
    try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
      while ((line = br.readLine()) != null) {
        System.out.println("Line =>"+line);
      }
    } catch (IOException e) {
      System.out.println("IOException in try block =>" + e.getMessage());
    }
  }
}

Kết quả nếu không tìm thấy tệp test.txt.

IOException in try-with-resources block =>test.txt (No such file or directory)

Xuất ra nếu tệp test.txt được tìm thấy.

Entering try-with-resources block
Line =>test line

Trong ví dụ này, chúng ta sử dụng một phiên bản của BufferedReader để đọc dữ liệu từ tệp test.txt.

Khai báo và khởi tạo BufferedReader bên trong câu lệnh try-with-resources đảm bảo rằng thể hiện của nó được đóng bất kể câu lệnh try hoàn thành bình thường hay ném một ngoại lệ.

Nếu một ngoại lệ xảy ra, nó có thể được xử lý bằng cách sử dụng các khối xử lý ngoại lệ hoặc từ khóa throw .

1. Ngoại lệ bị triệt tiêu

Trong ví dụ trên, các ngoại lệ có thể được ném ra khỏi câu lệnh try-with-resources khi:

  • Tập tin test.txt không được tìm thấy.
  • Đang đóng đối tượng BufferedReader.

Một ngoại lệ cũng có thể được ném ra khỏi khối try vì quá trình đọc tệp có thể không thành công vì nhiều lý do bất kỳ lúc nào.

Nếu các ngoại lệ được ném ra từ cả khối try và câu lệnh try-with-resources, thì ngoại lệ từ khối try được ném ra và ngoại lệ từ câu lệnh try-with-resources bị loại bỏ.

1.1 Truy xuất các ngoại lệ bị loại bỏ

Trong Java 7 trở lên, các ngoại lệ bị chặn có thể được truy xuất bằng cách gọi phương thức Throwable.getSuppressed() từ ngoại lệ do khối try ném ra .

Phương thức này trả về một mảng gồm tất cả các ngoại lệ bị loại bỏ. Chúng tôi nhận được các ngoại lệ bị đàn áp trong khối catch.

catch(IOException e) {
  System.out.println("Thrown exception=>" + e.getMessage());
  Throwable[] suppressedExceptions = e.getSuppressed();
  for (int i=0; i<suppressedExceptions.length; i++) {
    System.out.println("Suppressed exception=>" + suppressedExceptions[i]);
  }
}

2. Ưu điểm của việc sử dụng thử tài nguyên

Dưới đây là những lợi ích của việc sử dụng thử với tài nguyên:

2.1. khối finally không cần thiết để đóng tài nguyên

Trước khi Java 7 giới thiệu tính năng này, chúng ta phải sử dụng khối finally để đảm bảo rằng tài nguyên được đóng lại để tránh rò rỉ tài nguyên.

Đây là một chương trình tương tự như Ví dụ 1 . Tuy nhiên, trong chương trình này, chúng ta đã sử dụng khối cuối cùng để đóng tài nguyên.

Ví dụ 2: Đóng tài nguyên bằng khối cuối cùng

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/
import java.io.*;

class Main {
  public static void main(String[] args) {
    BufferedReader br = null;
    String line;

    try {
      System.out.println("Entering try block");
      br = new BufferedReader(new FileReader("test.txt"));
      while ((line = br.readLine()) != null) {
        System.out.println("Line =>"+line);
      }
    } catch (IOException e) {
      System.out.println("IOException in try block =>" + e.getMessage());
    } finally {
      System.out.println("Entering finally block");
      try {
        if (br != null) {
          br.close();
        }
      } catch (IOException e) {
        System.out.println("IOException in finally block =>"+e.getMessage());
      }

    }
  }
}

Đầu ra

Entering try block
Line =>line from test.txt file
Entering finally block 

Như chúng ta có thể thấy từ ví dụ trên, việc sử dụng khối finally để dọn dẹp tài nguyên làm cho code phức tạp hơn.

Chú ý cả khối try…catch trong khối finally? Điều này là do một IOException cũng có thể xảy ra trong khi đóng BufferedReader bên trong khối finally này nên nó cũng bị bắt và xử lý.

Câu lệnh try-with-resources thực hiện quản lý tài nguyên tự động . Chúng tôi không cần đóng tài nguyên một cách rõ ràng vì JVM tự động đóng chúng. Điều này làm cho mã dễ đọc hơn và dễ viết hơn.

2.2. thử tài nguyên với nhiều tài nguyên

Chúng ta có thể khai báo nhiều tài nguyên trong try-with-resources câu lệnh bằng cách phân tách chúng bằng dấu chấm phẩy;

Ví dụ 3: thử với nhiều tài nguyên

import java.io.*;
import java.util.*;
class Main {
  public static void main(String[] args) throws IOException{
    try (Scanner scanner = new Scanner(new File("testRead.txt")); 
      PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
      while (scanner.hasNext()) {
        writer.print(scanner.nextLine());
      }
    }
  }
}

Nếu chương trình này thực thi mà không tạo ra bất kỳ ngoại lệ nào, đối tượng Scanner sẽ đọc một dòng từ tệp testRead.txt và ghi nó vào một tệp mới testWrite.txt .

Khi nhiều khai báo được thực hiện, câu lệnh try-with-resources đóng các tài nguyên này theo thứ tự ngược lại. Trong ví dụ này, đối tượng PrintWriter được đóng trước và sau đó đối tượng Scanner được đóng lại.

3. Nâng cao với try tài nguyên với Java 9

Trong Java 7, có một hạn chế đối với câu lệnh try-with-resources. Tài nguyên cần được khai báo cục bộ trong khối của nó.

try (Scanner scanner = new Scanner(new File("testRead.txt"))) {
  // code
}

Nếu chúng ta khai báo tài nguyên bên ngoài khối trong Java 7, nó sẽ tạo ra một thông báo lỗi.

Scanner scanner = new Scanner(new File("testRead.txt"));
try (scanner) {
  // code
}

Để đối phó với lỗi này, Java 9 đã cải thiện câu lệnh try-with-resources để tham chiếu của tài nguyên có thể được sử dụng ngay cả khi nó không được khai báo cục bộ. Đoạn mã trên bây giờ sẽ thực thi mà không có bất kỳ lỗi biên dịch nào.

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!