Java Bài 37: Exception Tập 1 – Làm Quen Với Exception – Yellow Code Books

Rate this item:

Rating: 4.7/5. From 39 votes.

Please wait…

Chào mừng các bạn đã đến với bài học Java số 37, bài học về Exception. Đây là bài học trong chuỗi bài về lập trình ngôn ngữ Java của Yellow Code Books.

Trước khi bắt đầu đi chi tiết vào bài học, mình muốn các bạn biết rằng, ở đời không ai là hoàn hảo cả. Khi con người ta đủ lớn khôn, họ sẽ bắt đầu mắc lỗi. Điều quan trọng trong cuộc sống này là, không phải lúc nào bạn cũng cứ tránh xảy ra lỗi (vì nói thẳng ra là chẳng ai muốn dây vào lỗi hết), mà là nên học cách như thế nào đó để khi mắc lỗi rồi thì sẽ khắc phục và vượt qua lỗi lầm như thế nào thôi.

Ôi sao bài học hôm nay nặng triết lý quá vậy. Thực ra mình dẫn dụ tí cho vui. Đại ý của bài học hôm nay cũng sẽ gần như triết lý trên vậy. Tức là chúng ta sẽ xem xét đến một khía cạnh LỖI. LỖI ở đây là LỖI xảy ra trong các đoạn code mà chúng ta viết ra, một cách nghiêm túc và chuyên sâu.

Quay lại triết lý một chút, rằng một khi mà ứng dụng của chúng ta đủ lớn (cả về số dòng code lẫn tính năng), thì chắc chắn khi đó chúng ta sẽ khó kiểm soát được tính ổn định của logic ứng dụng. Và đến một lúc nào đó sẽ có LỖI xảy ra, LỖI nhẹ sẽ khiến hệ thống tung ra một số thông báo lạ lẫm đến người dùng, làm họ hoang mang, lỗi nặng hơn nữa sẽ làm cho ứng dụng bị kết thúc một cách đột ngột. Và cũng như triết lý trên kia, bạn không mong muốn LỖI xảy ra, nhưng bạn nên hiểu và phân biệt được các dạng LỖI trong Java, để có thể cung cấp cho ứng dụng một kịch bản đủ mạnh để vượt qua được LỖI mà không bị kết thúc một cách đột ngột, chí ít là cũng có thể thông báo một nội dung rõ ràng về tình trạng LỖI, hơn là để họ loay hoay với cái chức năng mà ứng dụng của bạn đã mất khả năng kiểm soát.

LỖI mà chúng ta đang nói đến được gọi chung với cái tên Exception trong Java. Và vì tầm quan trọng của nó, nên vấn đề sẽ được nói trong nhiều phần khác nhau. Mời bạn cùng làm quen với tập đầu tiên trong series về Exception này nhé.

Khái Niệm Exception

Exception có thể dịch ra tiếng Việt là Biệt lệ hoặc Ngoại lệ.

Tại sao chúng ta đang nói đến Lỗi, mà lại không phải là Error? Thực ra Exception có bao gồm Error trong đó. Exception là một khái niệm dùng để chỉ hiện tượng khi mà logic của ứng dụng bị tác động (theo chiều hướng xấu đi) bởi một vấn đề nào đó (có thể là lỗi hoặc cũng có thể không). Khi Exception diễn ra, nó làm cho chương trình bị lệch khỏi luồng chuẩn mà chúng ta đã lập trình ra, dẫn đến việc ứng dụng không thể xử lý được những logic của nó, hoặc có thể bị ngưng đột ngột (tình trạng này có thể gọi là “chết”, “đột tử”, hay “crash”).

Exception này diễn ra một cách không mong muốn. Và cho dù bạn đã chuẩn bị kỹ càng các tình huống, thì sự sai lệch luồng vẫn cứ mãi còn tiềm ẩn. Như một số ví dụ sau cho bạn thấy rõ hơn mối nguy hiểm thực sự đến từ đâu.

– Exception có thể xảy ra khi người dùng nhập dữ liệu sai lệch vào cho ứng dụng. Do vô tình hay cố ý. Như bài tập số 1 của bài hôm trước, nếu bạn muốn một số thực cho chương trình, mà người dùng lại nhập vào một ký tự!?!
– Hoặc khi ứng dụng tìm đọc một file nào đó mà lại không thể thấy được. Có thể file đó đã bị xóa trước đó rồi.
– Hay hệ thống bị hết bộ nhớ trong lúc ứng dụng đang chạy khiến cho ứng dụng không thể thực thi được các logic của nó.

Và còn nhiều tình huống khác nữa. Tóm lại như mình đã nói, Exception có thể được sinh ra từ lỗi nào đó, như lỗi code ẩu của lập trình viên, lỗi nhập liệu ẩu bởi người dùng. Và Exception còn được sinh ra từ các tình huống không phải là lỗi nữa, như hết bộ nhớ, như rớt kết nối mạng, như sự can thiệp vô tình bởi người dùng,…

Bạn đã hiểu tại sao lại gọi là Exception rồi đúng không nào. Để hiểu rõ hơn, chúng ta xem người ta phân loại Exception ra làm các loại nào nhé.

Phân Loại Exception

Để hiểu rõ và dễ dàng làm việc với Exception hơn, Java chia nó ra làm 3 loại như sau.

Checked Exception

Đây là những Exception không vượt qua được “cửa ải” của trình biên dịch. Tức là bạn sẽ nhận được các thông báo lỗi từ trình biên dịch khi mà nó phát hiện ra rằng bạn đang code các dòng code nào đó mà có khả năng xảy ra Exception. Và do bởi trình biên dịch đã xuất sắc phát hiện Exception cho bạn rồi nên mới có cái tên là Checked, tức là “đã kiểm duyệt”.

Nếu bạn muốn thử lòng trình biên dịch, cụ thể là Eclipse, thì hãy thử gõ các câu lệnh sau vào phương thức main nhé. Bạn chưa cần biết thực chất các dòng code sau nói lên điều gì đâu, nhưng bạn cứ thử gõ đi, đảm bảo import java.io.Filejava.io.FileReader nhé.

Minh họa Checked ExceptionMinh họa Checked Exception

Đấy, bạn đã thấy trình biên dịch phát hiện và báo lỗi. Nhưng khác với lỗi thông thường ở chỗ, nếu đó là lỗi, như bạn gõ nhầm System.out thành Ssytem.out chẳng hạn, thì bạn phải sửa lỗi ngay, còn với các Exception, chúng ta không sửa chữa gì cả, mà sẽ tìm cách “bắt” lỗi và bẻ luồng logic của ứng dụng theo một chiều hướng khác, mà ở bài sau chúng ta sẽ xem xét kỹ hơn.

Unchecked Exception

Exception này khá nguy hiểm, khi mà trình biên dịch không thể nào kiểm tra giúp bạn sự lai lệch luồng có thể xảy đến như trên kia. Và ứng dụng của bạn khi đến tay người dùng, khi người dùng đang thao tác thì… bùm! Ứng dụng “đột tử”.

Bởi vì Exception này xảy ra khi ứng dụng đang được thực thi, nên nó còn được gọi là Runtime Exception.

Thông thường khi ứng dụng bị chết đột ngột kiểu này, thì hệ thống vẫn có log cho chúng ta biết là lỗi như thế nào. Như mình cũng có nói đến log cho dạng này ở bên Android, được gọi là Stack Trace, bạn có thể tham khảo thêm.

Bạn có thể thử tạo ra Exception dạng này khi thử biên dịch đoạn code sau.

int num[] = {1, 2, 3, 4};
System.out.println(num[5]);

Đoạn code tưởng chừng như vô hại (vì không có báo lỗi gì khi code cả). Nhưng hệ thống sẽ không thể tìm thấy phần tử mảng thứ 5 nếu thực thi ứng dụng, vì mảng của chúng ta chỉ có khai báo 4 phần tử mà thôi. Và vì vậy ứng dụng bị chết khi không biết làm gì khác. Bạn có thể thử thực thi và xem log in ra console với dòng code trên nhé.

Error

Error ở đây cũng là Exception nhưng hơi khác với Exception một chút. Với hai loại Exception mà mình nói đến trên đây thực ra chưa phải là lỗi, bởi vì bạn không nên né tránh nó mà nên đối mặt và “bẻ” luồng ứng dụng sao cho khi gặp Exception này ứng dụng sẽ biết cách phản hồi đúng đắn. Bài sau chúng ta sẽ thực hành việc bẻ luồng này.

Còn Error thực sự là một điều không thể làm gì khác được. Nó vượt quá xử lý của chúng ta. Dù cho bạn biết trước có thể Error sẽ xảy ra. Khi ứng dụng bị Error, thường thì chúng ta chỉ có thể code lại chỗ đó cho nó khác đi rồi cập nhật một version mới cho ứng dụng chứ chẳng làm gì được. Chẳng hạn như khi bộ nhớ hệ thống đã bị cạn kiệt, hoặc khi bạn đang sử dụng một thư viện, và chẳng may một ngày nào đó một lớp hay một phương thức của thư viện đó không còn tìm thấy nữa.

Cây Phân Cấp Các Lớp Exception Trong Java

Bản thân các Exception được nói đến trên kia chính là các lớp trong Java. Khi ứng dụng bị sai lệch luồng, thì hệ thống cũng sẽ gán sự sai lệnh đó cụ thể cho một lớp Exception nào đó quản lý. Và bởi vì Exception được chia ra làm 3 loại như trên đây, nên bạn có thể xem sự phân cấp các lớp Exception này cũng chia ra làm 3 nhóm chính.

Cây phân cấp lớp ExceptionCây phân cấp lớp Exception

Nếu chưa hiểu gì cả về Exception thì bạn cứ xem qua nhé. Bài học sau chúng ta sẽ bắt đầu “bắt” các Exception dựa vào các lớp bên trong cây phân cấp theo sơ đồ trên. Và chúng ta còn có thể tự tạo ra các Exception riêng theo yêu cầu của ứng dụng nữa đấy.

Theo như cây phân cấp trên, thì lớp cao nhất liên quan đến toàn bộ bài học hôm nay là lớp Throwable. Chúng ta sẽ làm quen với Throwable và các phương thức hữu dụng của lớp cha này ở bài học sau, khi mà chúng ta đã biết cách bắt Exception như thế nào.

Hai lớp con của Throwable chính là ExceptionError. Trong Exception có hai loại lớp con. Một loại là RuntimeException và các con của nó, chúng là các Unchecked Exception như mình có nói đến ở trên kia, các Exception ở nhánh này sẽ không được kiểm duyệt bởi trình biên dịch, và vì vậy nó tiềm ẩn nhiều rủi ro khi ứng dụng đang chạy ở ngoài thực tế. Các con còn lại của Exception ngoài RuntimeException mà mình vừa nói đến trên đây là các Exception khác, chúng đều là các Checked Exception, nếu bạn có sử dụng các code có “đụng chạm” đến các Exception ở nhánh này sẽ bị hệ thống báo lỗi, như ví dụ mà bạn đã thấy trên kia. Còn các Exception bên nhánh Error cũng sẽ không được báo lỗi bởi hệ thống, nó sẽ tìm ẩn nguy cơ ứng dụng bị chết khi đang chạy mà chúng ta không thể lường trước được, như ở mục trên mình có nói đến.

Bài Tập Số 1

Bạn hãy thử code lại các dòng code của Bài tập số 1 của bài trước, nhưng lần này hãy để ý kỹ Exception mà console thông báo.

int i = Integer.parseInt("10");
float f = Float.parseFloat("4.5a");
         
System.out.println(i);
System.out.println(f);

Làm quen với NumberFormatExceptionLàm quen với NumberFormatException

Bạn hãy thử tìm hiểu xem NumberFormatException mà console hiển thị thuộc loại Exception nào mà chúng ta đã nói đến: Checked Exception, Unchecked Exception, hay Error?

Gợi ý: bạn có thể dùng tổ hợp Ctrl + click trái chuột (hoặc Command + click trái chuột với Mac) lên một lớp bất kỳ trong Eclipse để được dẫn đến khai báo của lớp đó trong hệ thống, bạn sẽ hiểu nhiều hơn về mối quan hệ của lớp đó với các lớp khác.

Bài Tập Số 2

Tương tự, bạn hãy thử code dòng sau và cho biết Exception của nó là gì, và Exception đó thuộc loại nào nhé.

int value = 10 / 0;
System.out.println(value);

Bài Tập Số 3

Bạn cũng hãy thử tìm hiểu xem code sau sẽ tạo ra Exception loại gì nhé.

String s = null;
System.out.println(s.length());

Như vậy với bài học hôm nay thì chúng ta đã làm quen với Exception trong Java là gì. Chúng ta sẽ còn vài bài nữa để có thể nói hết kiến thức thú vị về Exception này, các bạn theo dõi tiếp nhé.

Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:

Đánh giá 5 sao bên dưới mỗi bài nếu thấy thích.
Comment bên dưới mỗi bài nếu có thắc mắc.
Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.

Bài Kế Tiếp

Bài tiếp theo sẽ là phần chính liên quan đến sự “bắt” các Exception này, và điều chỉnh luồng ứng dụng sao cho hoặc có thể thông báo rõ ràng tình trạng lỗi cho người dùng, hoặc chạy một luồng mới.