Bài 15: Xử lý ngoại lệ (try-catch-finally) - Kiểm soát lỗi và tránh crash
🎯 Mục tiêu bài học
-
Phân biệt được lỗi cú pháp (Syntax Error) và lỗi thực thi (Runtime Error / Exception).
-
Sử dụng khối
try-catchđể "bắt" lỗi, giúp chương trình không bị văng (crash) giữa chừng. -
Hiểu vai trò của
finallytrong việc dọn dẹp tài nguyên (đóng file, ngắt kết nối DB). -
Chủ động ném ra lỗi với từ khóa
throw.
📖 Phần 1: Ngoại lệ (Exception) là gì?
-
Lỗi cú pháp (Syntax Error): Bạn viết sai chính tả (quên dấu
;, viết sai tên biến). Trình biên dịch báo gạch đỏ ngay lập tức, bạn không thể bấm chạy (Run) chương trình. -
Ngoại lệ (Exception / Runtime Error): Code viết đúng cú pháp 100%, chương trình chạy bình thường. Nhưng trong lúc đang chạy, một tình huống bất ngờ xảy ra: Người dùng nhập chữ vào ô tính toán thay vì số, chia một số cho 0, hoặc gọi API tới một Server đang bị sập.
Nếu bạn không chuẩn bị kịch bản đón đầu những "Ngoại lệ" này, ứng dụng sẽ lập tức hiển thị bảng lỗi đỏ lòm và tắt phụt (crash), khiến trải nghiệm người dùng cực kỳ tồi tệ.
📖 Phần 2: Cứu cánh try - catch
Cấu trúc try - catch hoạt động như một "lưới an toàn" cho những đoạn code rủi ro.
C#
try
{
// Chứa những dòng code CÓ NGUY CƠ sinh ra lỗi
int result = 10 / 0; // Lỗi chia cho 0 xảy ra tại đây!
Console.WriteLine("Ket qua la: " + result); // Dòng này bị bỏ qua
}
catch (Exception ex)
{
// Nếu có lỗi ở khối try, chương trình sẽ nhảy ngay vào khối catch thay vì bị crash
Console.WriteLine("Phat hien loi: " + ex.Message); // In ra dòng báo lỗi an toàn
}
Bắt lỗi chi tiết từng trường hợp
Thay vì bắt chung chung bằng Exception, code Backend chuẩn luôn ưu tiên bắt đích danh từng loại lỗi để có hướng xử lý phù hợp.
C#
try
{
int age = int.Parse(Console.ReadLine()); // Rủi ro: người dùng nhập chữ "Mười"
int year = 2026 / age; // Rủi ro: người dùng nhập số 0
}
catch (FormatException)
{
Console.WriteLine("Ban phai nhap bang so, khong duoc nhap chu!");
}
catch (DivideByZeroException)
{
Console.WriteLine("Tuoi khong the la so 0 duoc!");
}
catch (Exception ex) // Bắt tất cả các lỗi còn sót lại (Nên để ở cuối cùng)
{
Console.WriteLine("Co loi he thong: " + ex.Message);
}
📖 Phần 3: Khối dọn dẹp finally
Có những công việc bắt buộc phải làm cho dù chương trình chạy thành công hay xảy ra lỗi. Ví dụ: Mở kết nối Database ra thì dù query dữ liệu có bị lỗi hay không, cuối cùng vẫn phải đóng kết nối lại để giải phóng RAM.
Đó là nhiệm vụ của khối finally (Luôn luôn chạy).
C#
try
{
Console.WriteLine("1. Mo file database.txt");
Console.WriteLine("2. Dang doc du lieu...");
throw new Exception("File bi hong!"); // Giả lập sinh ra một lỗi
}
catch (Exception ex)
{
Console.WriteLine("3. Xu ly loi: " + ex.Message);
}
finally
{
Console.WriteLine("4. Luon luon chay vao day: Dong file database.txt lai.");
}
📖 Phần 4: Chủ động "ném" lỗi với throw
Đôi khi hệ thống không có lỗi về mặt kỹ thuật, nhưng lại vi phạm logic nghiệp vụ (Business Logic). Ví dụ: Rút tiền mà số dư âm. Lúc này, Backend Developer sẽ chủ động ném ra lỗi để các tầng khác xử lý.
C#
public void Withdraw(double amount, double balance)
{
if (amount > balance)
{
// Chủ động tạo ra một ngoại lệ và ném nó đi
throw new InvalidOperationException("So du khong du de rut tien!");
}
balance -= amount;
Console.WriteLine("Rut tien thanh cong.");
}
💻 Phần 5: Thực hành
Viết một chương trình nhập vào 2 số và thực hiện phép chia, áp dụng đầy đủ try-catch-finally:
C#
using System;
namespace Lesson15
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--- CHUONG TRINH CHIA HAI SO ---");
try
{
Console.Write("Nhap so bi chia: ");
int a = int.Parse(Console.ReadLine());
Console.Write("Nhap so chia: ");
int b = int.Parse(Console.ReadLine());
int result = a / b;
Console.WriteLine($"Ket qua: {a} / {b} = {result}");
}
catch (FormatException)
{
Console.WriteLine("[Loi] Vui long chi nhap so nguyen hop le!");
}
catch (DivideByZeroException)
{
Console.WriteLine("[Loi] Khong the chia mot so cho 0!");
}
catch (Exception ex)
{
// Ghi log lỗi hệ thống chưa lường trước
Console.WriteLine("[Loi He Thong] " + ex.Message);
}
finally
{
// Dù thành công hay thất bại, báo hiệu kết thúc phiên làm việc
Console.WriteLine("=> [Ket thuc phien giao dich. Da giai phong bo nho]");
}
Console.ReadLine();
}
}
}
📝 Tóm tắt bài học
-
try: Bao bọc đoạn code có nguy cơ văng lỗi. -
catch: Tóm gọn và xử lý lỗi một cách duyên dáng, giúp app tiếp tục chạy mà không bị crash. Cố gắng bắt lỗi cụ thể (nhưFormatException) trước khi bắt lỗi chungException. -
finally: Đảm bảo luôn được thực thi (để đóng File, ngắt DB, giải phóng bộ nhớ) bất chấp việc code có lỗi hay không. -
throw: Chủ động kích hoạt ngoại lệ dựa trên nghiệp vụ.
🛠 Bài tập thực hành
Yêu cầu: Xử lý lỗi vượt quá giới hạn mảng.
-
Khai báo một mảng số nguyên:
int[] numbers = { 10, 20, 30 };(Chỉ có chỉ số từ 0 đến 2). -
Yêu cầu người dùng nhập vào một vị trí (index) để xem giá trị.
-
Dùng khối
try-catchđể hứng lỗi. Nếu người dùng nhập số từ 3 trở lên, chương trình sẽ phát sinh lỗiIndexOutOfRangeException. Hãy bắt chính xác lỗi này và in ra câu thông báo:"Vị trí bạn nhập vượt quá giới hạn của mảng!".
All rights reserved