Từ Khóa throws (Throws Keywords)
Mục đích: Được sử dụng trong khai báo phương thức để chỉ định rằng phương thức đó có thể ném một hoặc nhiều ngoại lệ được kiểm tra (checked exceptions).
Vị trí sử dụng: Trong phần khai báo phương thức (sau tên phương thức và trước dấu ngoặc nhọn mở).
Cú pháp: ethodName() throws ExceptionType1, ExceptionType2 { ... }
Sử dụng với: Chủ yếu là các checked exceptions.
Nên khai báo từ khóa throws với ngoại lệ nào?
Trả lời: Chỉ ngoại lệ được kiểm tra (checked exceptions) , vì:
Ngoại Lệ Không Được Kiểm Tra (Unchecked Exceptions) dưới Sự Kiểm Soát: Các ngoại lệ không được kiểm tra thường là kết quả của lỗi lập trình mà bạn có thể sửa lỗi trong mã của mình. Chúng thường chỉ ra các lỗi cần được sửa chữa chứ không phải là các điều kiện cần xử lý.
Lỗi (Errors) ngoài Sự Kiểm Soát: Lỗi chỉ ra các vấn đề vượt ngoài tầm kiểm soát của ứng dụng và thường không thể xử lý bằng cách lập trình. Bạn thường không thể khôi phục từ các lỗi, vì vậy chúng không được khai báo trong chữ ký phương thức.
Ví dụ này minh họa cách sử dụng từ khóa throws để khai báo các ngoại lệ mà phương thức có thể ném ra, cũng như cách sử dụng khối try-catch để xử lý các ngoại lệ đó. Đây là cách throws giúp truyền đạt thông tin về ngoại lệ từ một phương thức lên phương thức gọi nó.
Ví dụ: Example.java
import java.io.FileNotFoundException;
import java.io.FileReader;
public class Example {
// Phương thức ném ra ngoại lệ FileNotFoundException
void openFile() throws FileNotFoundException {
FileReader file = new FileReader("nonexistentfile.txt"); // Sẽ gây ngoại lệ nếu file không tồn tại
}
// Phương thức gọi openFile và ném ngoại lệ FileNotFoundException
void readFile() throws FileNotFoundException {
openFile();
}
// Phương thức xử lý ngoại lệ từ readFile
void processFile() {
try {
readFile();
} catch (FileNotFoundException e) {
System.out.println("Ngoại lệ: " + e.getMessage());
}
}
public static void main(String[] args) {
Example obj = new Example();
obj.processFile();
System.out.println("Phần còn lại của chương trình...");
}
}
Kết quả của chương trình là:
Phần còn lại của chương trình...
Giải thích:
Khai báo ngoại lệ với throws:
↳ Phương thức openFile() có khả năng ném ra FileNotFoundException, nên nó sử dụng throws FileNotFoundException để thông báo cho các phương thức gọi nó rằng họ cần chuẩn bị để xử lý ngoại lệ này.
↳ Phương thức readFile() cũng ném ra FileNotFoundException, vì nó gọi openFile(). Do đó, readFile() cũng phải khai báo throws FileNotFoundException.
Xử lý ngoại lệ với try-catch:
↳ Phương thức processFile() gọi readFile(), nên nó cũng phải chuẩn bị để xử lý FileNotFoundException. Nó sử dụng khối try-catch để bắt ngoại lệ này và in thông báo lỗi nếu ngoại lệ xảy ra.
Ý nghĩa của throws:
↳ Từ khóa throws được sử dụng để truyền thông tin về các ngoại lệ có thể xảy ra từ một phương thức đến các phương thức gọi nó. Điều này cho phép phương thức gọi chuẩn bị xử lý ngoại lệ, hoặc truyền tiếp nó ra ngoài nếu không thể xử lý.
↳ Trong trường hợp này, throws giúp truyền thông tin về ngoại lệ từ openFile() đến readFile(), và từ readFile() đến processFile(), cho phép processFile() xử lý ngoại lệ đó.
Kết quả:
↳ Nếu file "nonexistentfile.txt" không tồn tại, ngoại lệ FileNotFoundException sẽ được ném ra trong phương thức openFile(), truyền qua readFile(), và cuối cùng bị bắt và xử lý trong khối catch của processFile().
↳ Nếu file tồn tại, chương trình sẽ không gặp lỗi và sẽ in ra "Phần còn lại của chương trình...".
Lưu ý: Nếu chúng ta gọi một phương thức khai báo một ngoại lệ, chúng ta phải hoặc là xử lý hoặc là khai báo ngoại lệ đó.
Trường hợp 1: Bắt ngoại lệ - Xử lý ngoại lệ bằng khối try-catch
Trong trường hợp này, bạn sử dụng khối try-catch để bắt ngoại lệ có thể xảy ra khi gọi phương thức. Điều này cho phép chương trình của bạn tiếp tục thực thi ngay cả khi ngoại lệ xảy ra. Khối try chứa đoạn mã có thể ném ngoại lệ, và khối catch sẽ bắt ngoại lệ đó và thực hiện một hành động cụ thể (ví dụ: in ra thông báo lỗi).
Ví dụ: Example.java
public class Example {
// Phương thức thực hiện phép chia
public static void divide(int numerator, int denominator) throws ArithmeticException {
// Kiểm tra và ném ngoại lệ nếu mẫu số là 0
if (denominator == 0) {
throw new ArithmeticException("Không thể chia cho 0");
}
// Thực hiện phép chia
int result = numerator / denominator;
System.out.println("Kết quả phép chia: " + result);
}
public static void main(String[] args) {
try {
// Gọi phương thức divide với mẫu số là 0
divide(10, 0);
} catch (ArithmeticException e) {
// Xử lý ngoại lệ khi mẫu số là 0
System.out.println("Ngoại lệ bị bắt: " + e.getMessage());
}
// Code tiếp theo vẫn chạy bình thường
System.out.println("Phần còn lại của chương trình...");
}
}
Kết quả của chương trình là:
Phần còn lại của chương trình...
Trong ví dụ này:
↳ Nếu Mẫu Số Không Bằng 0: Chương trình sẽ in kết quả phép chia.
↳ Nếu Mẫu Số Bằng 0: Ngoại lệ ArithmeticException sẽ bị bắt và xử lý, và chương trình sẽ in thông báo lỗi "Ngoại lệ bị bắt: Không thể chia cho 0". Sau đó, chương trình sẽ tiếp tục thực hiện phần còn lại của mã.
↳ Ví dụ này cho thấy cách xử lý ngoại lệ trong Java bằng cách sử dụng khối try-catch, giúp đảm bảo rằng chương trình không bị ngừng đột ngột do lỗi và tiếp tục thực hiện các phần còn lại của mã.
Trường hợp 2: Khai báo ngoại lệ - Sử dụng từ khóa throws
Nếu bạn không muốn xử lý ngoại lệ trong phương thức hiện tại, bạn có thể khai báo ngoại lệ đó bằng từ khóa throws trong chữ ký phương thức. Điều này thông báo cho người gọi phương thức rằng phương thức này có thể ném ra ngoại lệ và yêu cầu người gọi phải xử lý ngoại lệ đó hoặc tiếp tục khai báo lại ngoại lệ lên trên.
Ví dụ: AgeValidator.java
class AgeValidator {
// Phương thức kiểm tra tuổi, khai báo ngoại lệ IllegalArgumentException
public static void validateAge(int age) throws IllegalArgumentException {
if (age < 18) {
throw new IllegalArgumentException("Độ tuổi phải từ 18 trở lên.");
}
System.out.println("Độ tuổi hợp lệ: " + age);
}
// Phương thức chính gọi validateAge và khai báo ngoại lệ IllegalArgumentException
public static void main(String[] args) {
try {
checkAge(15); // Gọi phương thức với tuổi không hợp lệ
} catch (IllegalArgumentException e) {
System.out.println("Ngoại lệ: " + e.getMessage());
}
}
// Phương thức gọi validateAge, khai báo ngoại lệ IllegalArgumentException
public static void checkAge(int age) throws IllegalArgumentException {
validateAge(age);
}
}
Kết quả của chương trình là:
Trong ví dụ này:
↳ Nếu Tuổi Hợp Lệ (≥ 18): Phương thức validateAge in ra thông báo "Độ tuổi hợp lệ".
↳ Nếu Tuổi Không Hợp Lệ (< 18): Phương thức validateAge ném ngoại lệ IllegalArgumentException, phương thức checkAge không xử lý ngoại lệ này mà khai báo lại, và phương thức main sẽ bắt và xử lý ngoại lệ.
↳ Ví dụ này cho thấy cách khai báo ngoại lệ với từ khóa throws trong chữ ký của phương thức và yêu cầu người gọi phương thức xử lý ngoại lệ đó. Điều này giúp tách biệt logic kiểm tra và xử lý ngoại lệ, làm cho mã nguồn dễ bảo trì và rõ ràng hơn.
So sánh chi tiết hai từ khóa throw và throws trong Java
Để bạn dễ hình dung hơn, chúng ta sẽ so sánh chi tiết hai từ khóa throw và throws trong Java thông qua một bảng:
Tiêu chí | throw | throws |
---|---|---|
Chức năng | Dùng để ném ra một ngoại lệ (exception) trong phương thức. | Dùng để khai báo các ngoại lệ mà một phương thức có thể ném ra. |
Vị trí sử dụng | Bên trong thân phương thức. Thường đi kèm với từ khóa new để tạo một đối tượng ngoại lệ. | Sau danh sách tham số của phương thức, trước dấu ngoặc nhọn mở đầu khối lệnh của phương thức. |
Số lượng ngoại lệ | Chỉ ném một ngoại lệ tại một thời điểm. | Có thể khai báo nhiều ngoại lệ, cách nhau bằng dấu phẩy. |
Loại ngoại lệ | Dùng cho cả checked và unchecked exceptions. | Thường dùng cho checked exceptions. |
Khi nào sử dụng | Khi bạn muốn ném ra một ngoại lệ cụ thể ngay lập tức. | Khi bạn muốn thông báo rằng phương thức có thể ném ra ngoại lệ. |
Cú pháp | throw new ExceptionType("Thông báo lỗi"); | public void method() throws ExceptionType1, ExceptionType2 |
Xử lý ngoại lệ | Không xử lý ngoại lệ, chỉ ném ra. | Phương thức gọi cần xử lý ngoại lệ hoặc khai báo lại ngoại lệ. |
Chạy thời gian | Ném ra ngoại lệ tại thời điểm gặp throw . | Không ném ra ngoại lệ, chỉ thông báo phương thức có thể ném ra. |
Ví dụ | public void method() { throw new IOException("Error occurred"); } | public void method() throws IOException { // code có thể ném ra IOException } |
Ý nghĩa | Dùng để tạo và ném ngoại lệ cụ thể. | Dùng để khai báo phương thức có thể ném ra ngoại lệ nào đó. |
Khi nào sử dụng throw và throws:
↳ throw: Sử dụng khi muốn tạo ra một ngoại lệ tùy chỉnh để báo hiệu một điều kiện bất thường.
↳ throws: Sử dụng khi không muốn xử lý ngoại lệ ngay tại chỗ mà muốn để cho người gọi phương thức quyết định cách xử lý.