1. Các loại ngoại lệ
Tất cả các ngoại lệ được chia thành 4 loại, đây thực sự là các lớp kế thừa lẫn nhau.
Throwable
lớp học
Lớp cơ sở cho tất cả các ngoại lệ là Throwable
lớp. Lớp Throwable
chứa mã ghi ngăn xếp cuộc gọi hiện tại (dấu vết ngăn xếp của phương thức hiện tại) vào một mảng. lát nữa chúng ta sẽ tìm hiểu dấu vết ngăn xếp là gì.
Toán tử ném chỉ có thể chấp nhận một đối tượng xuất phát từ Throwable
lớp. Và mặc dù về mặt lý thuyết, bạn có thể viết mã như thế throw new Throwable();
, nhưng không ai thường làm điều này. Mục đích chính của Throwable
lớp là có một lớp cha duy nhất cho tất cả các ngoại lệ.
Error
lớp học
Lớp ngoại lệ tiếp theo là Error
lớp kế thừa trực tiếp Throwable
lớp. Máy Java tạo các đối tượng của Error
lớp (và hậu duệ của nó) khi xảy ra sự cố nghiêm trọng . Ví dụ: trục trặc phần cứng, không đủ bộ nhớ, v.v.
Thông thường, với tư cách là một lập trình viên, bạn không thể làm gì trong tình huống xảy ra lỗi như vậy (loại lỗi nên Error
được đưa ra) trong chương trình: những lỗi này quá nghiêm trọng. Tất cả những gì bạn có thể làm là thông báo cho người dùng rằng chương trình đang gặp sự cố và/hoặc ghi tất cả thông tin đã biết về lỗi vào nhật ký chương trình.
Exception
lớp học
Các lớp Exception
và RuntimeException
dành cho các lỗi phổ biến xảy ra trong hoạt động của nhiều phương thức. Mục tiêu của mỗi ngoại lệ được ném là bị bắt bởi một catch
khối biết cách xử lý nó đúng cách.
Khi một phương thức không thể hoàn thành công việc của nó vì một lý do nào đó, nó sẽ ngay lập tức thông báo cho phương thức đang gọi bằng cách đưa ra một ngoại lệ thuộc loại thích hợp.
Nói cách khác, nếu một biến bằng null
, phương thức sẽ đưa ra một NullPointerException
. Nếu các đối số không chính xác được truyền cho phương thức, nó sẽ đưa ra một tệp InvalidArgumentException
. Nếu phương thức vô tình chia cho 0, nó sẽ ném ra một ArithmeticException
.
RuntimeException
lớp học
RuntimeExceptions
là tập con của Exceptions
. Chúng tôi thậm chí có thể nói rằng đó RuntimeException
là phiên bản nhẹ của các ngoại lệ thông thường ( Exception
) — ít yêu cầu và hạn chế hơn đối với các ngoại lệ đó
Bạn sẽ học được sự khác biệt giữa Exception
và RuntimeException
sau này.
2. Throws
: kiểm tra ngoại lệ
Tất cả các ngoại lệ Java thuộc 2 loại: được chọn và không được chọn .
Tất cả các ngoại lệ kế thừa RuntimeException
hoặc Error
được coi là ngoại lệ không được kiểm tra . Tất cả những người khác được kiểm tra ngoại lệ .
Hai mươi năm sau khi các ngoại lệ được kiểm tra được giới thiệu, hầu hết mọi lập trình viên Java đều coi đây là một lỗi. Trong các khung hiện đại phổ biến, 95% tất cả các ngoại lệ đều không được chọn. Ngôn ngữ C#, gần như sao chép chính xác Java, không thêm các ngoại lệ được kiểm tra .
Sự khác biệt chính giữa ngoại lệ được kiểm tra và không được kiểm tra là gì ?
Có các yêu cầu bổ sung áp dụng cho các trường hợp ngoại lệ được kiểm tra . Nói một cách đại khái, chúng là:
yêu cầu 1
Nếu một phương thức đưa ra một ngoại lệ được kiểm tra , nó phải chỉ ra loại ngoại lệ trong chữ ký của nó . Theo cách đó, mọi phương thức gọi nó đều biết rằng "ngoại lệ có ý nghĩa" này có thể xảy ra trong đó.
Chỉ ra các ngoại lệ được kiểm tra sau các tham số phương thức sau throws
từ khóa (không sử dụng throw
từ khóa do nhầm lẫn). Nó trông giống như thế này:
type method (parameters) throws exception
Ví dụ:
kiểm tra ngoại lệ | ngoại lệ không được kiểm soát |
---|---|
|
|
Trong ví dụ bên phải, mã của chúng tôi đưa ra một ngoại lệ không được kiểm tra — không cần thực hiện thêm hành động nào. Trong ví dụ bên trái, phương thức đưa ra một ngoại lệ được kiểm tra , vì vậy throws
từ khóa được thêm vào chữ ký phương thức cùng với loại ngoại lệ.
Nếu một phương thức muốn đưa ra nhiều ngoại lệ được kiểm tra , thì tất cả chúng phải được chỉ định sau throws
từ khóa, được phân tách bằng dấu phẩy. Thứ tự không quan trọng. Ví dụ:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
yêu cầu 2
Nếu bạn gọi một phương thức đã kiểm tra các ngoại lệ trong chữ ký của nó, thì bạn không thể bỏ qua thực tế là nó sẽ ném chúng.
Bạn phải nắm bắt tất cả các ngoại lệ như vậy bằng cách thêm catch
các khối cho từng ngoại lệ hoặc bằng cách thêm chúng vào một throws
mệnh đề cho phương thức của bạn.
Như thể chúng ta đang nói, " Những ngoại lệ này quan trọng đến mức chúng ta phải nắm bắt chúng. Và nếu chúng ta không biết cách xử lý chúng, thì bất kỳ ai có thể gọi phương thức của chúng ta đều phải được thông báo rằng những ngoại lệ như vậy có thể xảy ra trong đó.
Ví dụ:
Hãy tưởng tượng rằng chúng ta đang viết một phương thức để tạo ra một thế giới có con người sinh sống. Số lượng người ban đầu được thông qua dưới dạng đối số. Vì vậy, chúng ta cần thêm trường hợp ngoại lệ nếu có quá ít người.
tạo trái đất | Ghi chú |
---|---|
|
Phương thức này có khả năng đưa ra hai ngoại lệ được kiểm tra :
|
Cuộc gọi phương thức này có thể được xử lý theo 3 cách:
1. Không bắt bất kỳ trường hợp ngoại lệ nào
Điều này thường được thực hiện khi phương pháp không biết cách xử lý tình huống đúng cách.
Mã số | Ghi chú |
---|---|
|
Phương thức gọi không nắm bắt các ngoại lệ và phải thông báo cho người khác về chúng: nó thêm chúng vào throws mệnh đề riêng của nó |
2. Nắm bắt một số ngoại lệ
Chúng tôi xử lý các lỗi chúng tôi có thể xử lý. Nhưng những cái chúng tôi không hiểu, chúng tôi ném chúng vào phương thức gọi. Để làm điều này, chúng ta cần thêm tên của chúng vào mệnh đề throws:
Mã số | Ghi chú |
---|---|
|
Người gọi chỉ bắt được một ngoại lệ được kiểm tra — LonelyWorldException . Ngoại lệ khác phải được thêm vào chữ ký của nó, chỉ ra nó sau throws từ khóa |
3. Bắt tất cả các ngoại lệ
Nếu phương thức không đưa ra ngoại lệ cho phương thức gọi, thì phương thức gọi luôn tự tin rằng mọi thứ đều hoạt động tốt. Và nó sẽ không thể thực hiện bất kỳ hành động nào để khắc phục các tình huống ngoại lệ.
Mã số | Ghi chú |
---|---|
|
Tất cả các ngoại lệ đều bị bắt trong phương pháp này. Người gọi sẽ tự tin rằng mọi thứ diễn ra tốt đẹp. |
3. Bắt nhiều ngoại lệ
Các lập trình viên thực sự ghét phải sao chép mã. Họ thậm chí còn đưa ra một nguyên tắc phát triển tương ứng — DRY : Don't Repeat Yourself. Nhưng khi xử lý các ngoại lệ, thường xảy ra trường hợp một try
khối được theo sau bởi một số catch
khối có cùng mã.
Hoặc có thể có 3 catch
khối có cùng mã và 2 catch
khối khác có mã giống hệt nhau. Đây là một tình huống tiêu chuẩn khi dự án của bạn xử lý các ngoại lệ một cách có trách nhiệm.
Bắt đầu với phiên bản 7, trong ngôn ngữ Java đã thêm khả năng chỉ định nhiều loại ngoại lệ trong một catch
khối. Nó trông đại khái như thế này:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
Bạn có thể có bao nhiêu catch
khối tùy thích. Tuy nhiên, một catch
khối duy nhất không thể chỉ định các ngoại lệ kế thừa lẫn nhau. Nói cách khác, bạn không thể viết catch ( Exception
| RuntimeException
e ), bởi vì RuntimeException
lớp kế thừa Exception
.
GO TO FULL VERSION