Nên sử dụng if else hay try catch exception?

Mình muốn viết code, đại ý là có một List<string> list, nếu tồn tại file list[i] thì thực hiện công việc XXX nào đó.
Theo như một bài báo mình mới được đọc, “Không có vé thì bị chặn lại là một bước tiến lớn so với nếu có vé mới được vào.” Từ ý tưởng đó, mình cho rằng

foreach (var FileName in list)
    try
    {
        XXX(FileName);
    }
    catch (System.IO.FileNotFoundException)
    {
        xxx("File not found");
    }

sẽ tốt hơn là

foreach (var FileName in list)
    if (System.IO.File.Exists(FileName)
    {
        XXX(FileName);
    }
    else
    {
        xxx("File not found");
    }

Liệu mình nghĩ như vậy có đúng không ạ? Xin mọi người cho ý kiến.

Với file nên dùng try/catch vì sau khi bạn check file có thể biến mất.

3 Likes

Theo tôi, bạn nên sử dụng try/catch bên trong hàm XXX(FillName). Như sau:

YYY(){
...
foreach (var FileName in list)
    XXX(FileName);
...
}

XXX(string FileName){
    if (System.IO.File.Exists(FileName)
    {
        throw System.IO.FileNotFoundException; /// Or throw an user define exception
    }
.....// the rest of XXX() method
}

hoặc là

XXX(string FileName){
    try{
         .....// the rest of XXX() method
    }
    catch(Exception){
        throw System.IO.FileNotFoundException; /// Or throw an user define exception
    }
}

Ưu điểm của cách này là ở YYY() bạn

  • ko cần quan tâm đến việc file có tồn tại hay ko,
  • và do đó code ở YYY() sẽ đơn giản và dễ đọc hơn.
  • ngoài ra, ở YYY() bạn ko nhất thiết phải handle cho exception này mà có thể handle ở những method gọi đến YYY()
2 Likes

Mình thấy cách hoàn toàn không sử dụng if sẽ tốt hơn là cách thứ nhất, bởi vì cái câu “Không có vé thì bị chặn lại là một bước tiến lớn so với nếu có vé mới được vào.”. Thông qua cái link của bạn mà mình đánh tích solution, mình thấy việc bỏ qua kiểm tra trước khi thực hiện bằng try catch sẽ giúp tăng tốc độ thực hiện khối câu lệnh và hạn chế lỗi

1 Like

Theo mình thì điều đó không cần thiết. Vì khi thực hiện khối try - catch, nó sẽ thực hiện các lệnh nằm bên trong khối try, nếu hàm XXX đó có bị Exception thì nó cũng sẽ qua khối catch bên ngoài

foreach (var FileName in list)
    try
    {
        XXX(FileName); //Nếu code chạy đúng,thoát khỏi khối try và catch. Ngược lại thì chạy vào khối catch
    }
    catch (System.IO.FileNotFoundException)
    {
        xxx("File not found"); //Chỉ thực hiện nếu khối try có Exception
    }

Trừ trường hợp “tự làm khó mình” đây trường hợp “có thật” do mình làm ra :laughing:
Hàm XXX(Config config) : kết nối CSDL SQLite sử dụng đối tượng config

public static void XXX(Config config)
{
    try
    {
        SQLiteConnection con = new SQLiteConnection(
        "Data Source = " + config.dataSource + "; "
        + "Version = " + config.version + "; "
        + "Password = " + config.password);
        con.Open();
    }
    catch(Exception)
    {
        Console.WriteLine(e.ToString());
    }
}

Hàm YYY() : đọc config từ file

public static void YYY()
try
    {
        //Muốn đọc config từ file temp
        SQLiteConfig config = SQLiteConfigJson.openTemp();
        XXX(config);
    }
catch
    {
        //Có file config tạo sẵn, không cần đọc file temp nữa
        SQLiteConfig config = SQLiteConfigJson.open();
        XXX(config);
    }
}

Chạy hàm YYY() với trường hợp muốn đọc file config có sẵn và không có file temp (đối tượng config lúc này sẽ là null) . Sau đó chạy tiếp hàm XXX(config) với một config = null, nó sẽ qua khối catch của hàm XXX và thực hiện câu lệnh Console.WriteLine(e.ToString()); : in ra message NullReferenceException ra màn hình console. Sau đó… thoát ra khối catch của hàm XXX và tiếp tục chạy trong khối try của hàm YYY! (đó là điều không mong muốn)
Quy trình như sau:

public static void YYY()
try
    {
        //Muốn đọc config từ file temp
        SQLiteConfig config = SQLiteConfigJson.openTemp(); //Không có temp -> config = null
        XXX(config); //Chạy vào trong hàm này
    }
catch
    {
        //Có file config tạo sẵn, không cần đọc file temp nữa
        SQLiteConfig config = SQLiteConfigJson.open();
        XXX(config);
    }
}
public static void XXX(Config config)
{
    try
    {
        //Lỗi! NullReferenceException. Do config lúc nãy = null
        //Bỏ qua try, sang catch
        SQLiteConnection con = new SQLiteConnection(
        "Data Source = " + config.dataSource + "; "
        + "Version = " + config.version + "; "
        + "Password = " + config.password);
        con.Open();
        SQLiteCommand com = new SQLiteCommand(con);
    }
    catch(Exception)
    {
        Console.WriteLine(e.ToString()); //Chạy câu lệnh này. Sau đó thoát khỏi catch
        //Chạy tiếp try của hàm YYY vì hàm catch này đã xử lý NullReferenceException rồi
    }
}

Vì thế đừng try - catch hay throw ra Exception trong các hàm con làm gì. Thêm rắc rối và khó sửa

Hay nói cách khác, tránh để các utility function bắt 1 exception (?)

Nếu sử dụng log thì chưa hẳn.

Cá nhân mình thì cái gì “if else” được thì “if else”, chừng nào không được thì mới “try catch”. Tóm lại là han chế dùng “try catch” tối đa.
Lý do là nó làm chậm chương trình.
Vậy trường hợp trên mình sẽ làm như sau:

foreach (var FileName in list)     {
    if (System.IO.File.Exists(FileName)
    {
        try
        {
            XXX(FileName);
        }
        catch (...)
        {
            xxx("File ...");
        }
    }
    else
    {
        xxx("File not found");
    }
}

Đồng ý :smile:
Nếu trường hợp đó mình biết các tình huống xẩy ra thì nên dùng if - else
Còn nếu với hàm có rủi ro bị exception cao (như truy vấn CSDL) thì phải try - catch

try-catch khi kết nối với CSDL thôi phải ko b, chứ khi truy vấn vẫn phải dùng try-catch à.
Giả sử m có câu truy vấn

var isNameExist = _context.TodoItems
                             .FirstOrDefault(t => t.Name == item.Name);

Nếu có lỗi thì isNameExist = null hay crash chương trình

Vấn đề là không phải lúc nào truy vấn cũng thành công. Kết quả chỉ trả về null nếu truy vấn thành công và CSDL không có bản ghi phù hợp. Nếu trong quá trình trao đổi, 2 máy bị mất kết nối với nhau thì chương trình sẽ bị crash nếu không có try-catch.

1 Like

Vậy csdl và app chạy cùng 1 máy thì vẫn phải dùng try catch để đam bảo ko bị crash sao ? Có cồng kềnh quá ko?

À ừ tất nhiên nếu cùng một máy thì khả năng lỗi là thấp (nhưng vẫn có thể có nhé), nếu cảm thấy an toàn thì không cần try catch. Nhưng mà phần lớn truy cập là qua mạng mà?

App server phải lấy ra từ database rồi mới truyền qua mạng mà, nên việc truy vấn CSDL cũng coi như từ 1 máy tính mà thôi.

java các ide tự sinh try catch hết rồi nếu nó thấy đoạn nào nghi nghi nên thôi vấn đề này ko phải lo:v

Thần thánh vậy sao @@.

vd các đoạn đọc ghi file trong c# mà ko tự viết try catch thì ko có còn bên java là ide vd như hồi em học là netbean nó tự sinh hết anh à

Cũng 1 thời gian dùng netbeans có thấy nó sinh ra đâu nhỉ @@.

bác ấn vào cái biểu tượng vàng vàng ấy là nó tự sinh cho mình mà

Tưởng nó tự động chèn @@.

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?