- 1 1. Giới thiệu
- 2 2. Xử lý ngoại lệ trong Java là gì?
- 3 3. throw là gì?
- 4 4. Throws là gì?
- 5 5. Sự khác nhau giữa throw và throws
- 6 6. Các thực hành tốt nhất khi sử dụng throws
- 7 7. Các mẫu thực tiễn trong xử lý ngoại lệ
- 8 8. Các Câu hỏi Thường gặp (FAQ)
- 8.5.1 Câu hỏi 1. Sự khác biệt chính giữa throw và throws là gì?
- 8.5.2 Câu hỏi 2. Tôi cần lưu ý gì khi sử dụng throws?
- 8.5.3 Câu hỏi 3. Có thể sử dụng throw và throws cùng nhau không?
- 8.5.4 Câu hỏi 4. Làm thế nào để khai báo nhiều ngoại lệ bằng throws?
- 8.5.5 Câu hỏi 5. Tôi có nên dùng throws với các unchecked exception không?
- 8.5.6 Câu hỏi 6. Có nên khai báo Exception hoặc Throwable trong một câu lệnh throws không?
- 8.5.7 Câu hỏi 7. Tôi luôn phải bắt các ngoại lệ được khai báo trong throws không?
- 8.5.8 Q8. What happens if I forget to write throws?
1. Giới thiệu
Khi bạn bắt đầu lập trình bằng Java, bạn sẽ không thể tránh khỏi thuật ngữ “xử lý ngoại lệ”. Trong số các từ khóa, “throw” và “throws” đặc biệt gây nhầm lẫn cho người mới bắt đầu vì chúng trông giống nhau nhưng có mục đích khác nhau.
Java là một ngôn ngữ được thiết kế với tính an toàn và độ bền vững, và nó cung cấp một cơ chế tích hợp để xử lý lỗi và các tình huống bất ngờ một cách thích hợp. Cơ chế này được gọi là “xử lý ngoại lệ”. Xử lý ngoại lệ đóng vai trò quan trọng trong việc nâng cao độ tin cậy và khả năng bảo trì của chương trình.
Trong bài viết này, chúng tôi tập trung vào cách sử dụng “java throws”, bắt đầu từ những kiến thức cơ bản về xử lý ngoại lệ và tiến tới các câu hỏi thường gặp và những bẫy phổ biến. Hướng dẫn này đặc biệt hữu ích cho bất kỳ ai còn băn khoan về sự khác biệt giữa “throw” và “throws”, hoặc muốn hiểu nơi và cách sử dụng throws một cách hiệu quả. Chúng tôi cũng bao gồm thông tin thực tế, mẹo và mã mẫu thường thấy trong các dự án thực tế, vì vậy hãy đọc đến cuối.
2. Xử lý ngoại lệ trong Java là gì?
Khi viết các chương trình Java, nhiều tình huống bất ngờ có thể xảy ra trong thời gian chạy. Ví dụ, tệp tin không tồn tại, lỗi chia cho 0, hoặc cố gắng truy cập một phần tử mảng ngoài phạm vi. Những tình huống này được gọi là “ngoại lệ”.
2.1 Khái niệm cơ bản của xử lý ngoại lệ
Xử lý ngoại lệ là một cơ chế phát hiện các tình huống bất thường (ngoại lệ) xảy ra trong quá trình thực thi chương trình và cho phép nhà phát triển xử lý chúng một cách thích hợp. Thay vì kết thúc chương trình đột ngột khi có ngoại lệ, Java cho phép ứng dụng phản hồi một cách có ý nghĩa dựa trên loại và nội dung của lỗi. Điều này cải thiện độ ổn định của ứng dụng và trải nghiệm người dùng.
2.2 Ngoại lệ đã kiểm tra và ngoại lệ chưa kiểm tra
Các ngoại lệ trong Java được chia thành hai loại chính.
Ngoại lệ đã kiểm tra
Ngoại lệ đã kiểm tra là những ngoại lệ phải được xử lý ở thời gian biên dịch. Ví dụ bao gồm IOException trong các thao tác với tệp tin. Những ngoại lệ này phải được bắt bằng khối try-catch hoặc truyền lên cho người gọi bằng khai báo throws.
try {
FileReader fr = new FileReader("data.txt");
} catch (IOException e) {
e.printStackTrace();
}
Ngoại lệ chưa kiểm tra
Ngoại lệ chưa kiểm tra là những ngoại lệ không yêu cầu phải xử lý bắt buộc ở thời gian biên dịch. Các ví dụ phổ biến bao gồm NullPointerException và ArrayIndexOutOfBoundsException, thường xuất phát từ lỗi lập trình. Mặc dù Java sẽ biên dịch mà không cần xử lý rõ ràng các ngoại lệ này, nhưng nên xử lý chúng khi cần thiết để tránh lỗi bất ngờ.
2.3 Tại sao cần xử lý ngoại lệ
Việc triển khai xử lý ngoại lệ đúng cách mang lại các lợi ích sau:
- Cải thiện độ ổn định của chương trình: Ngay cả khi có lỗi bất ngờ, chương trình vẫn có thể hiển thị thông báo phù hợp hoặc thực hiện logic phục hồi mà không bị sập.
- Dễ dàng gỡ lỗi hơn: Loại và thông điệp của ngoại lệ giúp xác định nguyên nhân của vấn đề nhanh hơn.
- Trải nghiệm người dùng tốt hơn: Thay vì kết thúc đột ngột với lỗi, hệ thống có thể cung cấp phản hồi có ý nghĩa hoặc các bước phục hồi.
Xử lý ngoại lệ trong Java là một kỹ năng thiết yếu để xây dựng các ứng dụng bền vững. Trong chương tiếp theo, chúng tôi sẽ giải thích các kiến thức cơ bản về “throw”.
3. throw là gì?
Trong Java, “throw” là một từ khóa dùng để tạo ra một ngoại lệ một cách có chủ đích. Mặc dù các ngoại lệ thường xuất hiện tự động trong quá trình thực thi, bạn có thể muốn tạo và ném một ngoại lệ khi một số điều kiện nhất định được đáp ứng — đây là lúc “throw” được sử dụng.
3.1 Cách sử dụng cơ bản của throw
“throw” tạo ra một đối tượng ngoại lệ và ném nó, gây ra một ngoại lệ. Cú pháp cơ bản như sau:
throw new ExceptionClass("Error message");
Ví dụ, nếu một đối số không hợp lệ được truyền vào, bạn có thể ném một ngoại lệ như sau:
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age must be zero or greater");
}
this.age = age;
}
Trong ví dụ này, một IllegalArgumentException được ném ra khi tuổi nhỏ hơn không.
3.2 Tại sao bạn có thể muốn ném ngoại lệ
Mục đích chính của việc sử dụng “throw” là thông báo ngay lập tức cho chương trình về các trạng thái không hợp lệ hoặc vi phạm quy tắc. Điều này giúp phát hiện lỗi sớm và ngăn chặn hành vi không mong muốn. Các ví dụ bao gồm:
- Khi đầu vào của người dùng không vượt qua quá trình kiểm tra
- Khi các tham số hoặc cấu hình không hợp lệ được truyền vào
- Khi logic nghiệp vụ ngăn cản việc xử lý tiếp theo
3.3 Lưu ý khi sử dụng throw
Khi một ngoại lệ được ném bằng “throw”, nó sẽ lan truyền tới caller trừ khi được xử lý bằng khối try-catch trong cùng phương thức. Đối với các ngoại lệ đã kiểm tra (như IOException), phương thức cũng phải khai báo “throws” trong chữ ký của nó. Đối với các ngoại lệ không kiểm tra, việc khai báo throws là tùy chọn, nhưng việc hiểu sự khác biệt giữa “throw” và “throws” là cần thiết để sử dụng đúng.
4. Throws là gì?
Khi viết chương trình Java, bạn có thể gặp từ khóa “throws” trong khai báo phương thức. Từ khóa throws được dùng để thông báo cho caller rằng phương thức có thể ném một hoặc nhiều ngoại lệ trong quá trình thực thi.
4.1 Cách sử dụng cơ bản của throws
Bằng cách chỉ định tên các lớp ngoại lệ trong khai báo phương thức, từ khóa throws sẽ lan truyền bất kỳ ngoại lệ nào có thể xảy ra bên trong phương thức tới caller của nó. Các ngoại lệ đã kiểm tra, đặc biệt, phải được khai báo với throws để đảm bảo caller xử lý chúng đúng cách. Ví dụ:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
// File reading process
}
Trong ví dụ này, constructor của FileReader có thể ném một IOException, vì vậy phương thức phải khai báo throws IOException.
4.2 Lan truyền ngoại lệ trong khai báo phương thức
Khi một phương thức khai báo throws, bất kỳ ngoại lệ nào xảy ra bên trong nó sẽ được lan truyền tới caller. Caller sau đó phải bắt ngoại lệ đó hoặc tiếp tục lan truyền bằng cách khai báo throws của riêng mình.
public void processFile() throws IOException {
readFile("test.txt"); // readFile throws IOException, so this method must also declare throws
}
4.3 Khai báo nhiều ngoại lệ
Nếu một phương thức có thể ném nhiều ngoại lệ, chúng có thể được khai báo bằng danh sách ngăn cách bằng dấu phẩy sau từ khóa throws.
public void connect(String host) throws IOException, SQLException {
// Network or database operations
}
4.4 Vai trò và lợi ích của throws
- Cải thiện khả năng đọc và bảo trì: Khai báo throws làm cho người đọc ngay lập tức biết phương thức có thể ném những loại ngoại lệ nào, giúp giao tiếp giữa các nhà phát triển tốt hơn.
- Rõ ràng trách nhiệm xử lý lỗi: throws buộc caller phải xử lý các ngoại lệ, thúc đẩy thiết kế hệ thống vững chắc và có cấu trúc.
- Hỗ trợ ngoại lệ tùy chỉnh: Các nhà phát triển có thể đưa các lớp ngoại lệ tùy chỉnh vào khai báo throws để xử lý các kịch bản lỗi phức tạp một cách hiệu quả hơn.
5. Sự khác nhau giữa throw và throws
Mặc dù thường bị nhầm lẫn, “throw” và “throws” có vai trò rất khác nhau trong cơ chế xử lý ngoại lệ của Java. Chương này làm rõ sự khác biệt giữa chúng và giải thích khi nào và cách sử dụng mỗi cái một cách chính xác.
5.1 Sự khác nhau về chức năng giữa throw và throws
| Item | throw | throws |
|---|---|---|
| Role | Actually generates an exception | Declares that a method may throw exceptions |
| Usage | Used inside methods to throw exception objects | Used in method declarations to specify throwable exceptions |
| Target | Exception objects created with new | Both checked and unchecked exceptions |
| Example | throw new IOException(“Error occurred”); | public void sample() throws IOException |
| When required | When intentionally raising an exception | When a method may throw checked exceptions |
5.2 Các tình huống sử dụng từng loại
- throw
- Được dùng khi bạn muốn tạo ra một ngoại lệ—ví dụ, khi phát hiện đầu vào không hợp lệ hoặc vi phạm quy tắc.
- Ví dụ: “Nếu tuổi nhỏ hơn không, throw IllegalArgumentException.”
- throws
- Được dùng khi một phương thức hoặc constructor có thể ném ngoại lệ và phải thông báo cho caller về điều đó.
- Ví dụ: “Sử dụng throws trong các phương thức xử lý thao tác file hoặc truy cập cơ sở dữ liệu, nơi các ngoại lệ được mong đợi.”

5.3 Ví dụ mã để so sánh
Ví dụ về throw:
public void setName(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be empty");
}
this.name = name;
}
Ví dụ về throws:
public void loadConfig(String path) throws IOException {
FileReader reader = new FileReader(path);
// Configuration loading process
}
5.4 Bảng tóm tắt
| Decision Point | throw | throws |
|---|---|---|
| Where it’s used | Inside a method | Method declaration |
| What it does | Generates an exception | Declares exception propagation |
| Who handles it | Thrown at the point of error | Handled by the caller |
| When required | Optional (only when needed) | Required for checked exceptions |
Vai trò của throw và throws là rõ ràng khác nhau, vì vậy việc hiểu cái nào nên dùng trong tình huống nào là bước đầu tiên hướng tới việc xử lý ngoại lệ mạnh mẽ.
6. Các thực hành tốt nhất khi sử dụng throws
Việc sử dụng throws một cách hiệu quả cải thiện khả năng đọc và bảo trì của các chương trình Java, đồng thời nâng cao chất lượng tổng thể của việc xử lý ngoại lệ. Chương này giới thiệu các thực hành được khuyến nghị và những lưu ý quan trọng thường được áp dụng trong phát triển thực tế.
6.1 Chỉ định các lớp ngoại lệ cụ thể
Trong khai báo throws, luôn chỉ định các lớp ngoại lệ cụ thể nhất có thể.
Tránh khai báo chung chung Exception hoặc Throwable.
Bằng cách sử dụng các ngoại lệ cụ thể như IOException hoặc SQLException, người gọi có thể xác định chính xác cách xử lý lỗi.
Ví dụ tốt:
public void saveData() throws IOException {
// File-saving process
}
Tránh làm như sau:
public void saveData() throws Exception {
// Too vague: unclear what exceptions may occur
}
6.2 Tận dụng cấu trúc phân cấp ngoại lệ
Vì các lớp ngoại lệ trong Java tạo thành một cấu trúc phân cấp, các ngoại lệ liên quan có thể được nhóm lại dưới một lớp cha khi phù hợp.
Tuy nhiên, tránh khái quát quá mức bằng các ngoại lệ cấp cao (ví dụ: Exception) vì điều này làm giảm tính rõ ràng và khiến việc xử lý lỗi trở nên khó khăn hơn.

6.3 Sử dụng thẻ @throws trong Javadoc
Khi cung cấp API hoặc thư viện, bạn nên tài liệu hoá các ngoại lệ bằng thẻ @throws trong các bình luận Javadoc.
Điều này giải thích rõ ràng các điều kiện gây ra ngoại lệ, giúp người dùng API thực hiện việc xử lý ngoại lệ đúng cách.
/**
* Reads a file.
* @param filePath Path of the file to read
* @throws IOException If the file cannot be read
*/
public void readFile(String filePath) throws IOException {
// ...
}
6.4 Tránh việc ném lại ngoại lệ không cần thiết
Tránh bắt ngoại lệ chỉ để ném lại chúng mà không thêm giá trị nào.
Nếu việc ném lại là cần thiết, hãy bọc ngoại lệ gốc trong một ngoại lệ tùy chỉnh hoặc bao gồm ngữ cảnh bổ sung hoặc thông tin ghi log.
6.5 Sử dụng các lớp ngoại lệ tùy chỉnh
Trong các ứng dụng doanh nghiệp và hệ thống lớn, thường định nghĩa các lớp ngoại lệ tùy chỉnh và đưa chúng vào khai báo throws.
Điều này giúp làm rõ nguyên nhân và trách nhiệm của lỗi, khiến hệ thống dễ bảo trì và mở rộng hơn.
public class DataNotFoundException extends Exception {
public DataNotFoundException(String message) {
super(message);
}
}
public void findData() throws DataNotFoundException {
// Throw when data is not found
}
Bằng cách sử dụng throws một cách thích hợp, bạn có thể phân phối trách nhiệm xử lý ngoại lệ, đơn giản hoá việc khắc phục sự cố, và xây dựng các ứng dụng Java đáng tin cậy và an toàn.
7. Các mẫu thực tiễn trong xử lý ngoại lệ
Việc xử lý ngoại lệ trong Java không chỉ bao gồm các khối try-catch đơn giản hay khai báo throws.
Chương này giới thiệu các mẫu thực tiễn và chiến lược thiết kế thường được sử dụng trong phát triển thực tế.
7.1 Quản lý tài nguyên với try-with-resources
Khi làm việc với tệp, kết nối mạng hoặc kết nối cơ sở dữ liệu, việc giải phóng tài nguyên đúng cách ngay cả khi có ngoại lệ xảy ra là rất quan trọng.
Từ Java 7, câu lệnh try-with-resources cho phép tài nguyên được đóng tự động.
try (FileReader reader = new FileReader("data.txt")) {
// File reading process
} catch (IOException e) {
System.out.println("Failed to read file: " + e.getMessage());
}
This syntax ensures that close() is called automatically, preventing resource leaks even if exceptions occur.
7.2 Xử lý Nhiều Ngoại lệ một cách Hiệu quả
Các hoạt động phức tạp có thể tạo ra nhiều loại ngoại lệ.
Kể từ Java 7, bạn có thể bắt nhiều ngoại lệ trong một câu lệnh catch duy nhất bằng tính năng multi-catch.
try {
methodA();
methodB();
} catch (IOException | SQLException e) {
// Handle both exceptions here
e.printStackTrace();
}
Bạn cũng có thể tách các khối catch để cung cấp xử lý tùy chỉnh cho từng loại ngoại lệ.
7.3 Các cân nhắc về Hiệu năng khi Xử lý Ngoại lệ
Mặc dù ngoại lệ mạnh mẽ, chúng không nên thay thế luồng điều khiển bình thường.
Việc tạo ra ngoại lệ tốn đáng kể tài nguyên vì cần tạo stack trace, vì vậy chúng nên được dùng cho các trường hợp thực sự bất thường.
Cách sử dụng không đúng (không khuyến nghị):
try {
int value = array[index];
} catch (ArrayIndexOutOfBoundsException e) {
// Bounds checking should be done beforehand
}
Cách sử dụng được khuyến nghị:
if (index >= 0 && index < array.length) {
int value = array[index];
} else {
// Out-of-range handling
}
7.4 Ghi nhật ký và Thông báo
Việc ghi nhật ký và cảnh báo đúng cách là cần thiết để khắc phục sự cố khi xảy ra ngoại lệ.
Các hệ thống doanh nghiệp thường sử dụng các framework ghi nhật ký (ví dụ: Log4j, SLF4J) để ghi lại thông tin chi tiết về ngoại lệ.
catch (Exception e) {
logger.error("An error has occurred", e);
}
7.5 Triển khai Logic Phục hồi Tùy chỉnh
Trong một số trường hợp, việc triển khai logic phục hồi như thử lại một thao tác, tải lại các tệp cấu hình, hoặc thông báo cho người dùng là hữu ích.
Thay vì kết thúc chương trình ngay lập tức, hãy cố gắng duy trì tính liên tục của dịch vụ bất cứ khi nào có thể.
Bằng cách áp dụng các kỹ thuật xử lý ngoại lệ thực tế, bạn có thể xây dựng các ứng dụng Java vừa đáng tin cậy vừa dễ bảo trì.
8. Các Câu hỏi Thường gặp (FAQ)
Dưới đây là các câu hỏi phổ biến từ người mới bắt đầu về xử lý ngoại lệ trong Java, đặc biệt liên quan đến “throws,” kèm theo câu trả lời.
Câu hỏi 1. Sự khác biệt chính giữa throw và throws là gì?
A1.
throw là một từ khóa thực sự tạo ra một ngoại lệ trong quá trình thực thi chương trình.
throws được dùng trong khai báo phương thức để thông báo khả năng rằng một phương thức có thể ném ngoại lệ.
→ Một cách nhớ dễ dàng: throw = “thực thi,” throws = “khai báo.”
Câu hỏi 2. Tôi cần lưu ý gì khi sử dụng throws?
A2.
Các ngoại lệ được khai báo bằng throws phải được người gọi bắt lại hoặc tiếp tục truyền lên bằng throws.
Đối với các checked exception, việc xử lý rõ ràng là bắt buộc.
Nếu bạn không bắt hoặc truyền tiếp ngoại lệ, chương trình sẽ không biên dịch được.
Câu hỏi 3. Có thể sử dụng throw và throws cùng nhau không?
A3.
Có.
Một mẫu thường gặp là ném một ngoại lệ bằng throw trong một phương thức và khai báo cùng một ngoại lệ bằng throws để nó được truyền lên người gọi.
Câu hỏi 4. Làm thế nào để khai báo nhiều ngoại lệ bằng throws?
A4.
Liệt kê chúng sau từ khóa throws, ngăn cách bằng dấu phẩy.
Ví dụ: public void sample() throws IOException, SQLException
Câu hỏi 5. Tôi có nên dùng throws với các unchecked exception không?
A5.
Các unchecked exception (các lớp kế thừa RuntimeException) không yêu cầu khai báo throws.
Tuy nhiên, throws có thể được dùng khi bạn muốn thông báo rõ ràng cho người gọi rằng một phương thức có thể ném một unchecked exception cụ thể, giúp cải thiện khả năng đọc và độ rõ ràng của API.
Câu hỏi 6. Có nên khai báo Exception hoặc Throwable trong một câu lệnh throws không?
A6.
Về mặt kỹ thuật có, nhưng không được khuyến nghị.
Khai báo các loại ngoại lệ quá rộng khiến người gọi không rõ những lỗi nào có thể xảy ra và làm cho việc xử lý đúng đắn ở phía gọi trở nên khó khăn hơn.
Hãy sử dụng các lớp ngoại lệ cụ thể càng nhiều càng tốt.
Câu hỏi 7. Tôi luôn phải bắt các ngoại lệ được khai báo trong throws không?
A7.
Đối với các ngoại lệ đã kiểm tra, người gọi phải bắt ngoại lệ hoặc truyền nó lên tiếp bằng từ khóa throws.
Nếu không làm như vậy sẽ gây ra lỗi biên dịch.
Các ngoại lệ không kiểm tra không yêu cầu bất kỳ hành động nào trong hai trường hợp trên.
Q8. What happens if I forget to write throws?
A8.
Nếu một phương thức ném một ngoại lệ đã kiểm tra nhưng không khai báo nó bằng throws, sẽ xảy ra lỗi biên dịch.
Đối với các ngoại lệ không kiểm tra, phương thức vẫn biên dịch bình thường ngay cả khi không có throws, nhưng vẫn nên thực hiện xử lý lỗi một cách thích hợp.
Sử dụng phần FAQ này để nâng cao hiểu biết của bạn về việc xử lý ngoại lệ trong Java.


