Các bài tập về xử lí ngoại lệ trong oop năm 2024

Khi đó, hệ thống cần có những cách xử lý riêng cho người dùng biết vấn đề đang xảy ra, và có những cách xử lý riêng cho hệ thống có thể tiếp tục hoạt động mà không bị ảnh hưởng quá nhiều.

Ví dụ:

  • Khi file không tồn tại, ứng dụng cần thông báo cho người dùng biết rằng file không tồn tại và yêu cầu người dùng chọn file khác, hoặc kiểm tra lại đường dẫn file.
  • Khi người dùng không cho phép ứng dụng chụp ảnh, ứng dụng cần thông báo cho người dùng biết rằng không thể chụp ảnh và yêu cầu người dùng cấp quyền.
  • Khi server bị mất điện, ứng dụng cần thông báo cho người dùng biết rằng không thể kết nối tới server và yêu cầu người dùng thử lại sau, hoặc kiểm tra xem đường truyền wifi, 3G, 4G có vấn đề gì không.

1.2 Exception là gì?

  • Exception dịch ra tiếng Việt có nghĩa là ngoại lệ. Exception là một sự kiện xảy ra trong quá trình thực thi chương trình, làm ảnh hưởng đến luồng thực thi của chương trình.

1.3 Checked và Unchecked Exception

1.3.1 Checked Exception

Các bài tập về xử lí ngoại lệ trong oop năm 2024
[Java Core] B7: Exception trong Java 32

  • Ảnh ví dụ: Khi ta thử đọc 1 file, IDE ngay lập tức thông báo có thể xảy ra FileNotFoundException (Ngoại lệ file không tồn tại) và yêu cầu ta phải xử lý nó.
  • Checked Exception thường là những lỗi phổ biến mà chúng ta có thể dự đoán được sẽ xảy ra cho một thao tác nào đó.
  • Ví dụ, khi đi dã ngoại, để phòng ngừa việc có mưa, ta mang theo áo mưa. Việc trời mưa là một ngoại lệ mà ta đã dự đoán trước và lên trước kế hoạch để xử lý nó.

1.3.2 Unchecked Exception

  • Đây là những Exception không được kiểm tra tại thời điểm biên dịch (compile time). Tức là chúng ta không nhận được thông báo lỗi từ trình biên dịch khi mà nó phát hiện ra rằng chúng ta chưa xử lý nó.
  • Đây là các exception khá nguy hiểm, khi mà chúng ta không thể dự đoán được chúng sẽ xảy ra khi nào. Bởi vì Exception này xảy ra khi ứng dụng đang thực thi, nên nó còn có thể gọi là Runtime Exception.
  • Ví dụ, khi một ứng dụng chia một số cho 0, nó sẽ ném ra một ngoại lệ ArithmeticException (Ngoại lệ toán học).
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 33
  • Trong đoạn code trên, nếu ta nhập vào 1 số không tồn tại trong mảng, nó sẽ bị một Exception ArrayIndexOutOfBoundsException (Ngoại lệ vượt quá giới hạn của mảng)., đây là một ví dụ về Unchecked Exception. Vì ta không thể biết được trước khi chạy chương trình, nó sẽ xảy ra khi nào.

1.4 Error

  • Error là một dạng ngoại lệ mà chúng ta không thể xử lý được. Error thường xảy ra khi mà hệ thống gặp phải những vấn đề nghiêm trọng, không thể khắc phục được.
  • Ví dụ, khi một ứng dụng chạy hết bộ nhớ, nó sẽ ném ra một ngoại lệ OutOfMemoryError (Lỗi hết bộ nhớ). Đây là một ví dụ về Error. Đây là một ngoại lệ ta không thể xử lý được, và nó thường xảy ra khi mà hệ thống gặp phải những vấn đề nghiêm trọng, không thể khắc phục được.

2. Bắt Exception với try-catch

Bài tập

  • Hãy viết chương trình nhập vào 1 String, và sử dụng Integer.parseInt để chuyển đổi String đó sang kiểu int. Thử nếu nhập vào 1 chuỗi không phải là số, xem chương trình sẽ báo lỗi như thế nào.
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 34
  • Khi chạy chương trình trên, ta sẽ nhận được một ngoại lệ NumberFormatException (Ngoại lệ không đúng định dạng số). Đây là một ví dụ về Unchecked Exception. Vì lúc compile, ta không nhận lỗi nào báo trước cả, do IDE không biết trước được String truyền vào khi chạy chương trình
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 35

2.1 Cách bắt Exception

  • Để bắt Exception, ta sử dụng cấu trúc try-catch. Cấu trúc try-catch sẽ giúp chúng ta bắt ngoại lệ, và xử lý nó một cách an toàn.
  • Cấu trúc try-catch có dạng như sau:
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 36
  • Trong đó:
    • try: Là một khối lệnh, chứa các câu lệnh có thể ném ra ngoại lệ.
    • catch: Là một khối lệnh, chứa các câu lệnh xử lý ngoại lệ. Trong đó, Exception e là một biến, chứa thông tin về ngoại lệ xảy ra.

2.2 Ví dụ

  • Ví dụ, ta sẽ sử dụng cấu trúc try-catch để bắt ngoại lệ NumberFormatException khi chuyển đổi một chuỗi không phải là số sang kiểu int.
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 37
  • Khi chạy chương trình trên, ta sẽ nhận được thông báo “Chuỗi không phải là số” khi chuyển đổi chuỗi “4.5a” sang kiểu float.

2.3 catch nhiều Exception

  • Ta cũng có thể bắt nhiều ngoại lệ trong cùng một cấu trúc try-catch, bằng cách sử dụng nhiều khối catch.

Bài tập

  • Hãy viết chương trình nhập vào số n, sau đó nhập vào n string. Sau đó nhập vào 1 số m, và in ra string thứ m. Nếu truy cập ngoài mảng, hãy in ra thông báo “Truy cập ngoài mảng”, còn nếu không in ra số được chuyển đổi từ string đó sang kiểu int, nếu không thể chuyển đổi được, hãy in ra thông báo “Chuỗi không phải là số”.\
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 38
  • Như ví dụ trên, ta thấy ta có thể catch nhiều Exception trong cùng một cấu trúc try-catch.

2.4 Catch Exception cha

  • Ta cũng có thể bắt Exception cha của một Exception con. Ví dụ, ta có thể bắt Exception cha của NumberFormatException là `ArithmeticException`2.

Bài tập

  • Tương tự bài tập trên, nhưng chỉ dùng 1 catch, và có bất kì lỗi gì xảy ra ta đều in ra “Lỗi xảy ra + tên lỗi”.
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 39
  • Như ví dụ trên, ta thấy ta có thể bắt Exception cha của NumberFormatException là `ArithmeticException`2.

3. Sử dụng finally

3.1 finally là gì?

  • finally là một khối lệnh, chứa các câu lệnh sẽ được thực thi sau khi khối lệnh try-catch kết thúc.
  • finally sẽ được thực thi sau khi khối lệnh try-catch kết thúc, bất kể có ngoại lệ xảy ra hay không.

3.2 Ví dụ

  • Ví dụ, ta sẽ sử dụng finally để đóng Scanner sau khi sử dụng xong.
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 40
  • Trong đoạn code trên, ta sẽ đóng Scanner sau khi sử dụng xong, bất kể có ngoại lệ xảy ra hay không.

Tác dụng

  • finally thường được sử dụng để giải phóng tài nguyên, như đóng file, đóng kết nối, đóng Scanner, … Đây là một practice nên làm đó là giải phóng tài nguyên sau khi sử dụng xong, tránh lãng phí tài nguyên.

3.3 Một số câu hỏi

3.3.1 Tại sao không sử dụng Exception là xong mà cần catch Exception cụ thể, có nhiều class Exception con

  • Khi sử dụng Exception là xong, ta sẽ bắt được tất cả các Exception, nhưng đôi khi ta cần xử lý một cách cụ thể cho từng Exception. Vì khi có lỗi xảy ra, cứ chỉ báo là đã có lỗi xảy ra thì thứ nhất người dùng rất khó chịu, ta khi sửa lỗi cũng không biết lỗi xảy ra là gì, ở đâu. Thứ hai, ta cũng không thể xử lý lỗi một cách cụ thể.
  • Việc catch đúng Exception cụ thể sẽ giúp ta xử lý lỗi một cách cụ thể. Ví dụ: Nếu lỗi là chia cho 0, ta báo cho người dùng rằng họ nhập sai để họ biết sai ở đâu và sửa lại, còn nếu lỗi là không tìm thấy file, ta báo cho người dùng biết rằng file không tồn tại để họ biết cần phải tạo file mới. Hoặc nếu là các lỗi người dùng không hiểu được, ta cần báo các lỗi cụ thể, có định danh rõ ràng để lập trình viên có thể biết và sửa lỗi
  • Ví dụ, trong window đôi lúc ta bị màn hình xanh, ta có các mã lỗi kiểu như `ArithmeticException`5, `ArithmeticException`6, … những mã lỗi này không phục vụ cho người dùng hiểu, nhưng người dùng có thể dùng nó để báo cáo, và lập trình viên có thể dùng nó để sửa lỗi.

3.3.2 Có thể Try không có Catch không?

  • Có thể, nhưng ta cần có một khối finally để giải phóng tài nguyên.
  • Ví dụ, ta có thể sử dụng try-finally để giải phóng tài nguyên, mà không cần catch Exception.
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 41

4. Cây phân cấp Exception

  • Trong Java, Exception được phân cấp theo một cấu trúc cây, với `ArithmeticException`7 là gốc của cây, `ArithmeticException`8 và `ArithmeticException`2 là 2 nhánh con của `ArithmeticException`7.
    Các bài tập về xử lí ngoại lệ trong oop năm 2024
    [Java Core] B7: Exception trong Java 42
  • Interface Iterable nhằm ám chỉ những class bên dưới kế thừa có tính “có thể ném ra được”
  • Lí do tại sao cần 1 cây Exception sẽ được giải thích bên dưới, mục câu hỏi tại sao không catch mọi exception

4.1 Throw, tung ra ngoại lệ

  • Đến hiện tại, ta đã biết các Exception có sẵn trong Java, và cách bắt nó bằng cấu trúc try-catch.
  • Ta nhận thấy, các Exception đều triển khai từ `ArithmeticException`7, và có thể tung ra (throw) một Exception bằng cách sử dụng từ khóa `ArrayIndexOutOfBoundsException`2.

Ví dụ: Ta cần nhập vào một số là tuổi của người dùng, ta sử dụng `ArrayIndexOutOfBoundsException`3 của `ArrayIndexOutOfBoundsException`4 để nhập vào, nhưng nếu người dùng nhập vào một chuỗi không phải là số, ta sẽ tung ra một Exception `ArrayIndexOutOfBoundsException`5 (Ngoại lệ nhập không đúng).