Các câu lệnh try-Catch lồng nhau có còn là mùi mã nếu được lồng trong một vòng lặp không?


8

Tôi đã nghe nói rằng các câu lệnh thử bắt lồng thường có thể là một mùi mã, vì vậy tôi tự hỏi liệu tình huống này có phải là một ngoại lệ hay không. Nếu không, một số cách tốt để tái cấu trúc là gì?

Mã của tôi trông như sau:

try{
    X x = blah;
    otherStuff;
    for (int i = 0; i < N; i++){
        try{
            String y = Integer.toString(i);
            f(x);
        }
        catch(Exceptions1 e1){
            System.err.println(... + y + ...);
            System.exit(0);
        }
}
catch(Exceptions2 e2){
    ...
}

Tôi đang sử dụng Exceptionsở đây để chỉ một đa bắt.

e2được sử dụng để bắt ngoại lệ ném bằng cách khởi tạo xvà làm otherStuff. Lý tưởng nhất là tôi chỉ có hai lần thử bắt xung quanh hai dòng đó, nhưng tôi sử dụng xtrong vòng lặp của mình và muốn tránh các cảnh báo "chuyển nhượng không sử dụng" gây ra bằng cách khởi tạo thành null bên ngoài bắt thử.

e1không bị bắt e2bởi vì tôi muốn cung cấp cho người dùng thông tin về các chi tiết lặp và do đó muốn có một khối bắt trong vòng lặp.

Câu trả lời:


6

Nếu bạn e2bắt, như bạn nói, chỉ để bắt lỗi trong việc khởi tạo xvà thực hiện, otherStuffbạn có thể trích xuất nó thành một phương thức riêng biệt. Điều này cũng tách biệt logic độc đáo và cho phép bạn có khả năng đặt tên có ý nghĩa otherStuff.

public X Foo() {
    try{
        X x = blah;
        otherStuff;

        return x;
    }
    catch(Exceptions2 e2){
        ...
    }
}

public void Bar() {    
    X x = Foo();
    for (int i = 0; i < N; i++){
        try{
            String y = Integer.toString(i);
            f(x);
        }
        catch(Exceptions1 e1){
            System.err.println(... + y + ...);
            System.exit(0);
        }
    }
}

Câu trả lời này có ý nghĩa nhất đối với tình huống của tôi, vì nó cho phép tôi phân tách chức năng bắt lỗi thay vì cung cấp bí danh cho việc bắt nội bộ, dù sao vẫn sẽ xảy ra
Weasemunk

7

Trừ khi bạn có ý định xử lý toàn bộ vòng lặp bên trong cho dù có ngoại lệ xảy ra hay không, mã của bạn về cơ bản là tương đương với

try{
    X x = blah;
    otherStuff;
    for (...){ 
       f(x)
    }
}
catch(Exceptions1 e1){
    ...
}
catch(Exceptions2 e2){
    ...
}

mà không cần làm tổ

Nếu bạn vẫn cần xử lý ngoại lệ bên trong, hãy cấu trúc lại ngoại lệ bên trong và phương thức kèm theo của nó thành một phương thức mới. Điều này cũng có thêm lợi ích khi buộc bạn phải suy nghĩ về các cách khác để xử lý vòng lặp bên trong; ngoại lệ có thể trở nên rất tốn kém về hiệu suất, nếu rất nhiều trong số chúng bị ném.


Tôi hiểu ý bạn là gì. Tôi đã thêm một số chi tiết để xác định rõ hơn tình hình của mình. Trong vòng lặp bên trong, tôi muốn sử dụng giá trị của y, phụ thuộc vào phép lặp i (Tôi thực sự đang sử dụng một cho mỗi, nhưng điều này sẽ giúp tôi hiểu ý). Cái bắt bên trong của tôi sẽ nói điều gì đó về giá trị của y khi nó bị bắt, trong khi cái bắt bên ngoài không phụ thuộc vào vòng lặp. Tôi vẫn có thể đi xung quanh việc lồng nhau hay tôi bị khóa bởi quyết định cung cấp thông tin phụ thuộc vào vòng lặp?
Weasemunk

Tôi vẫn nghĩ rằng tôi sẽ cấu trúc lại vòng lặp bên trong thành phương thức riêng của mình, nơi bạn có thể làm bất cứ điều gì bạn muốn với ngoại lệ.
Robert Harvey

Cảm ơn, tôi đã kết hợp câu trả lời của bạn với @Martin Brendan để tạo ra một giải pháp sạch.
Weasemunk

3

Tôi có một vài quan sát về câu hỏi của bạn:

  1. Trong ví dụ bạn cung cấp, bạn không cần ngoại lệ. Bạn chỉ cần kiểm tra chuỗi y, ghi lại bất kỳ lỗi nào và thoát khỏi vòng lặp. Không có gì là đặc biệt về việc y không hợp lệ và cần phải đăng nhập. Thực tế bạn đang sử dụng ngoại lệ trong trường hợp này là dấu hiệu của mùi mã.

  2. Các trường hợp ngoại lệ Multi-Catch không thực sự được sử dụng để gói các dải mã lớn và bắt bất kỳ thứ gì có thể sai. Chúng có nghĩa là để giúp phân biệt giữa các ngoại lệ trong trường hợp một phần mã duy nhất có thể tạo ra một loạt các ngoại lệ khác nhau. Vì bạn đang sử dụng các ngoại lệ bắt đa dạng như một cách tiếp cận "bắt tất cả", điều này cho thấy mùi mã.

  3. Sẽ không có ý nghĩa gì khi đặt thử bắt trong vòng lặp trừ khi bạn có kế hoạch tiếp tục lặp qua phần còn lại của vòng lặp ngay cả khi tìm thấy ngoại lệ trên một trong các yếu tố. Mã mẫu của bạn cho thấy bạn có kế hoạch thoát khỏi vòng lặp nếu có bất kỳ một mục nào là ngoại lệ.

Tôi nghĩ rằng bạn có thể tốt hơn với một cái gì đó như:

try
{
     var x = blah;
     DoStuff();
     foreach(var i in icollection) // i is an int
     {
          var y = SomethingDependentOnI(i);

          // check y for explicit exceptional states
          if (IsSomethingWrongWithY(y))
               throw new Exception1(y);
     }
}
catch (Exception1 e1)
{
}
catch (Exception2 e2)
{
}

Điều này rõ ràng hơn nhiều, nhưng nó vẫn phải chịu những vấn đề được mô tả ở trên.


Cảm ơn các bình luận. 1 + 2 không thực sự phù hợp với mã thực tế, nhưng tôi nghĩ rằng quan điểm của bạn về việc ném vào vòng lặp có ý nghĩa
Weasemunk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.