ĐỊNH NGHĨA KIỂU NGOẠI LỆ MỚI
Thông thường, khi viết mã sử dụng các thư viện có sẵn, lập trình viên cần xử lý các ngoại lệ có sẵn mà các phương thức trong thư viện đó ném để tạo ra được những chương trình có khả năng chống chịu lỗi cao. Còn nếu ta viết các lớp để cho các lập trình viên khác sử dụng trong chương trình của họ, ta có thể cần định nghĩa các kiểu ngoại lệ đặc thù cho các sự cố có thể xảy ra khi các lớp này được dùng trong các chương trình khác.
Một lớp ngoại lệ mới cần phải là lớp chuyên biệt hóa của một lớp ngoại lệ có sẵn để loại ngoại lệ mới có thể dùng được với cơ chế xử lý ngoại lệ thông thường. Một lớp ngoại lệ điển hình chỉ chứa hai hàm khởi tạo, một hàm không lấy đối số và truyền một thông báo lỗi mặc định cho hàm khởi tạo của lớp cha, một hàm lấy một xâu kí tự là thông báo lỗi tùy chọn và truyền nó cho hàm khởi tạo của lớp cha.
Còn trong phần lớn các trường hợp, ta chỉ cần một lớp con rỗng với một cái tên thích hợp là đủ. Nên dành cho mỗi loại sự cố nghiêm trọng một lớp ngoại lệ được đặt tên thích hợp để tăng tính trong sáng của chương trình.
Nên chọn lớp ngoại lệ cơ sở là một lớp có liên quan. Ví dụ, nếu định tạo lớp ngoại lệ mới cho sự cố phép chia cho 0, ta có thể lấy lớp cha là lớp ngoại lệ cho tính toán số học là ArithmeticException. Nếu không có lớp ngoại lệ có sẵn nào thích hợp làm lớp cha, ta nên xét đến việc ngoại lệ mới nên thuộc loại được kiểm tra (checked) hay không (unchecked). Nếu cần bắt buộc chương trình sử dụng xử lý ngoại lệ, ta dùng loại được kiểm tra, nghĩa là là lớp con của Exception nhưng không phải lớp con của RuntimeException. Còn nếu có thể cho phép chương trình ứng dụng bỏ qua ngoại lệ này, ta chọn lớp cha là RuntimeException.
NGOẠI LỆ VÀ CÁC PHƯƠNG THỨC CÀI ĐÈ
Giả sử ta viết một lớp con và cài đè một phương thức của lớp cha. Có những ràng buộc gì về việc ném ngoại lệ từ trong phương thức của lớp con?
Ta nhớ lại nguyên lý “Các đối tượng thuộc lớp con có thể được đối xử như thể chúng là các đối tượng thuộc lớp cha”. Nói cách khác, đoạn mã nào chạy được với một lớp cha cũng phải chạy được với bất kì lớp nào được dẫn xuất từ lớp đó. Đặt trong ngữ cảnh cụ thể hơn của lời gọi phương thức từ tham chiếu tới lớp cha, ta có quy tắc rằng phương thức cài đè chỉ được ném các kiểu ngoại lệ đã được khai báo tại phiên bản của lớp cha, hoặc ngoại lệ thuộc các lớp con của các kiểu nói trên, hoặc không ném ngoại lệ nào.
Hình 11.14: Ném ngoại lệ từ phương thức cài đè
Lấy ví dụ trong Hình 11.14. Phương thức blah() vốn được viết cho đối số thuộc kiểu A. Khối catch (ExceptionA e) trong đó bắt loại ngoại lệ mà phương thức methodA() của A có thể ném. B là lớp con của A, do đó có thể chạy blah() cho kiểu B. Nếu khối catch nói trên không thể bắt được các loại ngoại lệ mà phiên bản methodA() của B ném, thì phương thức blah() không thể được coi là chạy được đối với kiểu con của A. Do đó, kiểu ExceptionB mà phiên bản methodA() của B tuyên bố có thể ném phải được định nghĩa là một lớp dẫn xuất từ lớp ExceptionA.
Tổng kết
- Một phương thức có thể ném ngoại lệ khi gặp sự cố trong khi đang chạy
- Một ngoại lệ là một đối tượng thuộc kiểu Exception hoặc lớp con của Exception.
- Trình biên dịch không quan tâm đến các ngoại lệ kiểu RuntimeException. Các ngoại lệ kiểu RuntimeException không bắt buộc phải được phương thức xử lý bằng khối try/catch hay khai báo throws để né.
- Tất cả các loại ngoại lệ mà trình biên dịch quan tâm được gọi là các ngoại lệ được kiểm tra. Các ngoại lệ còn lại (các loại RuntimeException) được gọi là ngoại lệ không được kiểm tra.
- Một phương thức ném một ngoại lệ bằng lệnh throw, tiếp theo là một đối tượng ngoại lệ mới.
- Các phương thức có thể ném một ngoại lệ loại được kiểm tra phải khai báo ngoại lệ đó với dạng throws Exception
- Nếu một phương thức của ta gọi một phương thức có ném ngoại lệ loại được kiểm tra, phương thức đó phải đảm bảo rằng ngoại lệ đó được quan tâm xử lý.
- Nếu muốn xử lý ngoại lệ phát sinh từ một đoạn mã, ta bọc đoạn mã đó vào trong một khối try/catch và đặt phần mã xử lý ngoại lệ/khắc phục sự cố vào trong khối catch.
- Nếu không định xử lý ngoại lệ, ta có thể ‘né’ ngoại lệ bằng khai báo throws.
- Nếu một lớp con cài đè phương thức của lớp cha thì phiên bản của lớp con chỉ được ném các kiểu ngoại lệ đã được khai báo tại phiên bản của lớp cha, hoặc ngoại lệ thuộc các lớp con của các kiểu nói trên, hoặc không ném ngoại lệ nào