Trong hướng dẫn này, chúng ta sẽ tìm hiểu về câu lệnh try-with-resources để tự động đóng tài nguyên.
Câu try-with-resources
lệnh 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 tôi khai báo try-with-resources
câu lệnh bằng,
- khai báo và khởi tạo tài nguyên trong
try
mệnh đề. - xác đị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 giao diện AutoClosable .
Hãy để chúng tôi lấy một ví dụ thực hiện try-with-resources
câu lệnh.
Ví dụ 1: thử 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 tôi sử dụng một phiên bản của BufferedReader để đọc dữ liệu từ test.txt
tệp.
Khai báo và khởi tạo BufferedReader bên trong try-with-resources
câu lệnh đảm bảo rằng thể hiện của nó được đóng bất kể try
câu lệnh 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 ném .
Các trường hợp 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 try-with-resources
câu lệnh khi:
- The file
test.txt
is not found. - Closing the
BufferedReader
object.
Một ngoại lệ cũng có thể được ném ra khỏi try
khối 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ả try
khối và try-with-resources
câu lệnh, thì ngoại lệ từ try
khối sẽ được ném ra và ngoại lệ từ try-with-resources
câu lệnh bị loại bỏ.
Truy xuất các trường hợp 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 Throwable.getSuppressed()
phương thức từ ngoại lệ do try
khối ném ra .
Phương thức này trả về một mảng 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 catch
khối.
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]);
}
}
Ưu điểm của việc sử dụng thử tài nguyên
Dưới đây là những lợi thế của việc sử dụng thử với tài nguyên:
1. khối cuối cùng 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 tôi phải sử dụng finally
khối để đả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 tôi đã 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
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 finally
khối để dọn dẹp tài nguyên làm cho mã phức tạp hơn.
Chú ý cả try...catch
khối trong finally
khối? Điều này là do một IOException
cũng có thể xảy ra trong khi đóng BufferedReader
cá thể bên trong finally
khối này nên nó cũng bị bắt và xử lý.
Câu try-with-resources
lệnh thực hiện quản lý tài nguyên tự động . Chúng ta không cần phải đó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. 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, Scanner
đối tượng sẽ đọc một dòng từ testRead.txt
tệp và ghi nó vào một testWrite.txt
tệp mới .
Khi nhiều khai báo được thực hiện, try-with-resources
câu lệnh đóng các tài nguyên này theo thứ tự ngược lại. Trong ví dụ này, PrintWriter
đối tượng được đóng trước và sau đó Scanner
đối tượng được đóng.
Nâng cao tính năng thử với tài nguyên trong Java 9
Trong Java 7, có một hạn chế đối với try-with-resources
câu lệnh. 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 tiến try-with-resources
câu lệnh để 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.