Xin chào! Trong bài giảng trước, chúng ta đã làm quen với khía cạnh ngoại lệ của ngôn ngữ Java và xem các ví dụ về cách làm việc với chúng. Hôm nay chúng ta sẽ xem xét sâu hơn về cấu trúc của chúng và cũng học cách viết các ngoại lệ của riêng mình :)
Các loại ngoại lệ
Như chúng tôi đã nói, có rất nhiều lớp ngoại lệ trong Java, gần 400! Nhưng chúng đều được chia thành các nhóm nên khá dễ nhớ. Nó trông như thế này: Tất cả các ngoại lệ đều có một lớp tổ tiên chungThrowable
. Hai nhóm lớn đến từ nó - ngoại lệ (Ngoại lệ) và lỗi (Lỗi). Lỗi là lỗi nghiêm trọng trong quá trình thực thi chương trình liên quan đến hoạt động của máy ảo Java. Trong hầu hết các trường hợp, Lỗi không cần phải xử lý vì nó chỉ ra một số lỗi nghiêm trọng trong mã. Các lỗi nổi tiếng nhất: StackOverflowError
- ví dụ, xảy ra khi một phương thức gọi chính nó không ngừng và OutOfMemoryError
- xảy ra khi không có đủ bộ nhớ để tạo đối tượng mới. Như bạn có thể thấy, trong những tình huống này, hầu hết không có gì đặc biệt để xử lý - mã chỉ được viết sai và cần phải được làm lại. Trên thực tế, các ngoại lệ là các ngoại lệ: một tình huống ngoại lệ, ngoài kế hoạch xảy ra trong khi chương trình đang chạy. Đây không phải là những lỗi nghiêm trọng như Lỗi nhưng chúng cần được chúng ta chú ý. Tất cả các ngoại lệ được chia thành 2 loại - đã chọn ( đã chọn ) và không được chọn ( không được chọn ). Tất cả các ngoại lệ được kiểm tra đều đến từ Exception
. "Có thể kiểm chứng" nghĩa là gì? Chúng tôi đã đề cập một phần điều này trong bài giảng trước : “...trình biên dịch Java biết về các ngoại lệ phổ biến nhất và biết chúng có thể xảy ra trong những tình huống nào.” Ví dụ, anh ta biết rằng nếu một lập trình viên đọc dữ liệu từ một tệp trong mã, thì có thể dễ dàng phát sinh tình huống tệp đó không tồn tại. Và có rất nhiều tình huống như vậy mà anh ấy có thể đoán trước được. Do đó, trình biên dịch sẽ kiểm tra trước mã của chúng tôi để tìm các trường hợp ngoại lệ có thể xảy ra. Nếu tìm thấy chúng, nó sẽ không biên dịch mã cho đến khi chúng tôi xử lý chúng hoặc chuyển tiếp chúng lên trên cùng. Loại ngoại lệ thứ hai là “không được kiểm tra”. Họ đến từ lớp học RuntimeException
. Chúng khác với những gì đang được thử nghiệm như thế nào? Có vẻ như cũng có một loạt các lớp khác nhau xuất phát RuntimeException
và mô tả các ngoại lệ thời gian chạy cụ thể. Sự khác biệt là trình biên dịch không mong đợi những lỗi này. Có vẻ như anh ấy đang nói: “Tại thời điểm viết mã, tôi không tìm thấy điều gì đáng ngờ, nhưng đã xảy ra sự cố khi nó đang hoạt động. Rõ ràng là có lỗi trong mã!” Và thực sự là như vậy. 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 viên. Và trình biên dịch rõ ràng không thể cung cấp tất cả các tình huống không chính xác có thể xảy ra mà mọi người có thể tự tạo ra :) Do đó, nó sẽ không kiểm tra việc xử lý các trường hợp ngoại lệ như vậy trong mã của chúng tôi. Bạn đã gặp phải một số trường hợp ngoại lệ không được kiểm tra:
ArithmeticException
xảy ra khi chia cho số 0ArrayIndexOutOfBoundsException
Xảy ra khi cố gắng truy cập vào một ô bên ngoài mảng.
Cách ném ngoại lệ của bạn
Tất nhiên, những người tạo ra Java không thể cung cấp tất cả các tình huống đặc biệt có thể phát sinh trong chương trình. Có quá nhiều chương trình trên thế giới và chúng quá khác nhau. Nhưng không sao cả, vì bạn có thể tạo ngoại lệ của riêng mình nếu cần. Điều này được thực hiện rất dễ dàng. Tất cả bạn phải làm là tạo lớp học của riêng bạn. Tên của nó phải kết thúc bằng “Exception”. Trình biên dịch không cần điều này, nhưng các lập trình viên đọc mã của bạn sẽ hiểu ngay rằng đây là một lớp ngoại lệ. Ngoài ra, bạn cần chỉ rõ lớp đó đến từ lớpException
. Điều này đã cần thiết cho trình biên dịch và hoạt động chính xác. Ví dụ: chúng ta có lớp Dog - Dog
. Chúng ta có thể dắt chó đi dạo bằng cách sử dụng walk()
. Nhưng trước đó, chúng ta cần kiểm tra xem thú cưng của mình có đeo vòng cổ, dây xích và rọ mõm hay không. Nếu thiếu bất kỳ thứ nào trong số này, chúng tôi sẽ đưa ra ngoại lệ của riêng mình DogIsNotReadyException
. Mã của nó sẽ trông như thế này:
public class DogIsNotReadyException extends Exception {
public DogIsNotReadyException(String message) {
super(message);
}
}
Để chỉ ra rằng một lớp là một ngoại lệ, bạn cần viết mở rộng Ngoại lệ sau tên lớp: điều này có nghĩa là “lớp bắt nguồn từ ngoại lệ của lớp”. Trong hàm tạo, chúng ta sẽ chỉ gọi hàm tạo của lớp Exception
bằng một dòng message
- nó sẽ hiển thị cho người dùng một thông báo từ hệ thống mô tả lỗi đã xảy ra. Đây là những gì nó sẽ trông giống như trong mã lớp của chúng tôi:
public class Dog {
String name;
boolean isCollarPutOn;
boolean isLeashPutOn;
boolean isMuzzlePutOn;
public Dog(String name) {
this.name = name;
}
public static void main(String[] args) {
}
public void putCollar() {
System.out.println("The collar is on!");
this.isCollarPutOn = true;
}
public void putLeash() {
System.out.println("The leash is on!");
this.isLeashPutOn = true;
}
public void putMuzzle() {
System.out.println("The muzzle is on!");
this.isMuzzlePutOn = true;
}
public void walk() throws DogIsNotReadyException {
System.out.println("Let's go for a walk!");
if (isCollarPutOn && isLeashPutOn && isMuzzlePutOn) {
System.out.println("Hurrah, let's go for a walk!" + name + " I am glad!");
} else {
throw new DogIsNotReadyException("Dog " + name + "not ready for a walk! Check your gear!");
}
}
}
Bây giờ phương thức của chúng tôi walk()
đưa ra một ngoại lệ DogIsNotReadyException
. Điều này được thực hiện bằng cách sử dụng từ khóa throw
. Như chúng tôi đã nói trước đó, một ngoại lệ là một đối tượng. Do đó, trong phương pháp của chúng tôi, khi một tình huống đặc biệt xảy ra - con chó bị thiếu thứ gì đó - chúng tôi tạo một đối tượng lớp mới DogIsNotReadyException
và ném nó vào chương trình bằng cách sử dụng từ throw
. walk()
Chúng tôi thêm các lần ném vào chữ ký phương thức DogIsNotReadyException
. Nói cách khác, trình biên dịch hiện biết rằng lệnh gọi phương thức walk()
có thể dẫn đến một ngoại lệ. Vì vậy, khi chúng ta gọi nó ở đâu đó trong chương trình, ngoại lệ sẽ cần được xử lý. Hãy thử thực hiện điều này theo phương thức main()
:
public static void main(String[] args) {
Dog dog = new Dog("Mukhtar");
dog.putCollar();
dog.putMuzzle();
dog.walk();//Unhandled exception: DogIsNotReadyException
}
Không biên dịch, ngoại lệ không được xử lý! Hãy bọc mã của chúng tôi trong một khối try-catch
để xử lý ngoại lệ:
public static void main(String[] args) {
Dog dog = new Dog("Mukhtar");
dog.putCollar();
dog.putMuzzle();
try {
dog.walk();
} catch (DogIsNotReadyException e) {
System.out.println(e.getMessage());
System.out.println("Checking equipment! Is the collar on?" + dog.isCollarPutOn + "\r\n Is the leash on?"
+ dog.isLeashPutOn + "\r\n Are you wearing a muzzle?" + dog.isMuzzlePutOn);
}
}
Bây giờ hãy nhìn vào đầu ra của giao diện điều khiển:
Ошейник надет!
Намордник надет!
Собираемся на прогулку!
Собака Мухтар не готова к прогулке! Проверьте экипировку!
Проверяем снаряжение! Ошейник надет? true
Поводок надет? false
Намордник надет? true
Hãy xem đầu ra của bảng điều khiển đã trở nên giàu thông tin hơn biết bao! Chúng tôi thấy từng bước diễn ra trong chương trình; Chúng tôi biết lỗi xảy ra ở đâu và ngay lập tức nhận thấy chính xác con chó của chúng tôi đang thiếu gì :) Đây là cách chúng tôi tạo ra các ngoại lệ của riêng mình. Như bạn có thể thấy, không có gì phức tạp. Và mặc dù các nhà phát triển Java không buồn thêm một ngoại lệ đặc biệt vào ngôn ngữ của họ đối với những con chó được trang bị không đúng cách, nhưng chúng tôi đã sửa lỗi giám sát của họ :)
GO TO FULL VERSION