Phần này chỉ bàn về ngoại lệ (Exception
) ở mức độ người dùng.
Các lỗi ngoại lệ có tính hệ thống thường là tai họa và không nên cố tránh né chúng.
Trường hợp phổ biến là bắt lỗi ngoại lệ khi xử lý dữ liệu do người dùng nhập vào.
Khi phát sinh lỗi ngoại lệ, ngăn xếp (stack
) chạy chương trình được nhả
ra cho tới khi bắt được lỗi ngoại lệ đầu tiên.
try
{
readText("dummyFile");
}
catch (FileException e)
{
// ...
}
Bạn chủ động sinh ra lỗi ngoại lệ nhờ throw
.
Có thể bắt nhiều lỗi ngoại lệ khác nhau,
và cũng có finally
để thi hành phần mã dẫu trước đó có lỗi hoặc không.
try
{
throw new StringException("Lỗi rồi, không qua được nhé!");
}
catch (FileException e)
{
// ...
}
catch (StringException e)
{
// ...
}
finally
{
// ...
}
Tuy nhiên, cần nhớ rằng việc dùng chặn phạm vi thường tốt hơn là try-finally
.
Có thể đặt ra các kiểu lỗi ngoại lệ mới nhờ lớp thừa kế từ Exception
:
class UserNotFoundException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__) {
super(msg, file, line);
}
}
throw new UserNotFoundException("D-Man đang đi du lịch.");
Trình biên dịch có thể đảm bảo hàm không gây ra các hiệu ứng phụ nguy hiểm nào.
Các hàm đánh dấu bởi nothrow
được trình biên dịch đánh dấu
và ngăn nó phát sinh bất kỳ lỗi ngoại lệ nào.
bool lessThan(int a, int b) nothrow
{
writeln("thế giới nguy hiểm");
// Chuỗi output có thể gây lỗi ngoại lệ, nhưng vì hàm này
// được đánh dấu với `nothrow`, trình biên dịch sẽ không
// cho phép bạn dùng writeln như ở trên. Nói cách khác,
// bạn không thể biên dịch đoạn mã nguồn này.
return a < b;
}
Lưu ý thêm là trình biên dịch có thể nội suy tính chất cho các mã mẫu một cách tự động.
Điều quan trọng cần nhớ là cần tránh dùng assert
và cả lập trình hợp đồng khi xử lý dữ liệu đầu vào
từ người dùng, bởi vì assert
hay hợp đồng đều bị bỏ qua khi trình biên dịch
không bật cờ dò lỗi (debug
). Bạn có thể dùng thư viện
std.exception
trong đó hàm
enforce
có vai trò tương tự assert
, nhưng nó phát sinh lỗi ngoại lệ (Exception
)
thay vì AssertError
.
import std.exception : enforce;
float magic = 1_000_000_000;
enforce(magic + 42 - magic == 42, "Dấu chấm động... vui nhỉ :)");
// throw custom exceptions
// quăng lỗi ngoại lệ do lập trình viên định nghĩa
enforce!StringException('a' != 'A', "Phân biệt hoa thường.");
Thư viện std.exception
cũng có nhiều thứ khác. Ví dụ khi lỗi không đến
mức tai họa, bạn có thể bỏ qua nhờ
collect:
import std.exception : collectException;
auto e = collectException(aDangerousOperation());
if (e)
writeln("Hàm phát sinh lỗi ", e);
Khi viết mã kiểm tra mức độ đơn vị,
bạn giả lập các lỗi quăng ra với assertThrown
.