Nên thử bắt bắt đi trong hay ngoài vòng lặp?


184

Tôi có một vòng lặp trông giống như thế này:

for (int i = 0; i < max; i++) {
    String myString = ...;
    float myNum = Float.parseFloat(myString);
    myFloats[i] = myNum;
}

Đây là nội dung chính của một phương thức có mục đích duy nhất là trả về mảng float. Tôi muốn phương thức này trả về nullnếu có lỗi, vì vậy tôi đặt vòng lặp bên trong một try...catchkhối, như thế này:

try {
    for (int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    }
} catch (NumberFormatException ex) {
    return null;
}

Nhưng sau đó tôi cũng nghĩ đến việc đặt try...catchkhối bên trong vòng lặp, như thế này:

for (int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
    } catch (NumberFormatException ex) {
        return null;
    }
    myFloats[i] = myNum;
}

Có bất kỳ lý do, hiệu suất hoặc cách khác, để thích cái này hơn cái kia?


Chỉnh sửa: Sự đồng thuận dường như là sạch hơn khi đặt vòng lặp bên trong thử / bắt, có thể bên trong phương thức riêng của nó. Tuy nhiên, vẫn còn tranh luận về cái nào nhanh hơn. Ai đó có thể kiểm tra điều này và trở lại với một câu trả lời thống nhất?


2
Tôi không biết về hiệu suất, nhưng mã có vẻ sạch hơn với thử bắt bên ngoài vòng lặp for.
Jack B Nhanh nhẹn

Câu trả lời:


131

HIỆU SUẤT:

Hoàn toàn không có sự khác biệt về hiệu suất trong đó các cấu trúc thử / bắt được đặt. Trong nội bộ, chúng được triển khai như một bảng phạm vi mã trong cấu trúc được tạo khi phương thức được gọi. Trong khi phương thức đang thực thi, các cấu trúc thử / bắt hoàn toàn không có hình ảnh trừ khi xảy ra ném, sau đó vị trí của lỗi được so sánh với bảng.

Đây là một tài liệu tham khảo: http://www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html

Bảng được mô tả về một nửa xuống.


Được rồi, vì vậy bạn đang nói không có sự khác biệt ngoại trừ thẩm mỹ. Bạn có thể liên kết đến một nguồn?
Michael Myers

2
Cảm ơn. Tôi cho rằng mọi thứ có thể đã thay đổi kể từ năm 1997, nhưng họ hầu như không làm cho nó kém hiệu quả hơn.
Michael Myers

1
Hoàn toàn là một từ khó khăn. Trong một số trường hợp, nó có thể ức chế tối ưu hóa trình biên dịch. Không phải là một chi phí trực tiếp, nhưng nó có thể là một hình phạt hiệu suất gián tiếp.
Tom Hawtin - tackline

2
Đúng vậy, tôi đoán rằng tôi nên trị vì sự nhiệt tình của mình một chút, nhưng thông tin sai lệch đang làm tôi lo lắng! Trong trường hợp tối ưu hóa, vì chúng tôi không thể biết hiệu suất sẽ bị ảnh hưởng theo cách nào, tôi đoán đã quay lại để thử và kiểm tra (như mọi khi).
Jeffrey L Whitledge

1
không có sự khác biệt về hiệu năng, chỉ khi mã chạy mà không có ngoại lệ.
Onur Bıyık

72

Hiệu suất : như Jeffrey đã nói trong bài trả lời của mình, trong Java, nó không tạo ra nhiều khác biệt.

Nói chung , để dễ đọc mã, việc bạn chọn nơi bắt ngoại lệ tùy thuộc vào việc bạn có muốn vòng lặp tiếp tục xử lý hay không.

Trong ví dụ của bạn, bạn trở lại khi bắt một ngoại lệ. Trong trường hợp đó, tôi sẽ đặt thử / bắt xung quanh vòng lặp. Nếu bạn chỉ đơn giản muốn bắt một giá trị xấu nhưng tiếp tục xử lý, hãy đặt nó vào bên trong.

Cách thứ ba : Bạn luôn có thể viết phương thức ParseFloat tĩnh của riêng bạn và xử lý ngoại lệ được xử lý trong phương thức đó thay vì vòng lặp của bạn. Làm cho việc xử lý ngoại lệ bị cô lập với chính vòng lặp!

class Parsing
{
    public static Float MyParseFloat(string inputValue)
    {
        try
        {
            return Float.parseFloat(inputValue);
        }
        catch ( NumberFormatException e )
        {
            return null;
        }
    }

    // ....  your code
    for(int i = 0; i < max; i++) 
    {
        String myString = ...;
        Float myNum = Parsing.MyParseFloat(myString);
        if ( myNum == null ) return;
        myFloats[i] = (float) myNum;
    }
}

1
Nhìn gần hơn. Anh ấy thoát khỏi ngoại lệ đầu tiên trong cả hai. Tôi cũng nghĩ điều tương tự lúc đầu
kervin

2
Tôi nhận thức được, đó là lý do tại sao tôi nói trong trường hợp của anh ấy, vì anh ấy trở lại khi anh ấy gặp vấn đề nên tôi sẽ sử dụng một biện pháp chụp bên ngoài. Để rõ ràng, đó là quy tắc tôi sử dụng ...
Ray Hayes

Mã đẹp, nhưng thật không may, Java không có các tham số xa xỉ.
Michael Myers

ByRef? Đã rất lâu kể từ khi tôi chạm vào Java!
Ray Hayes

2
Một số người khác đã đề xuất TryPude trong C # /. Net cho phép bạn thực hiện phân tích cú pháp an toàn mà không phải xử lý các trường hợp ngoại lệ, hiện đã được sao chép và phương thức này có thể sử dụng lại. Đối với câu hỏi ban đầu, tôi thích vòng lặp bên trong bẫy hơn, nó trông có vẻ sạch hơn ngay cả khi không có vấn đề về hiệu suất ..
Ray Hayes

46

Được rồi, sau khi Jeffrey L Whitledge nói rằng không có sự khác biệt về hiệu suất (tính đến năm 1997), tôi đã đi và thử nghiệm nó. Tôi đã chạy điểm chuẩn nhỏ này:

public class Main {

    private static final int NUM_TESTS = 100;
    private static int ITERATIONS = 1000000;
    // time counters
    private static long inTime = 0L;
    private static long aroundTime = 0L;

    public static void main(String[] args) {
        for (int i = 0; i < NUM_TESTS; i++) {
            test();
            ITERATIONS += 1; // so the tests don't always return the same number
        }
        System.out.println("Inside loop: " + (inTime/1000000.0) + " ms.");
        System.out.println("Around loop: " + (aroundTime/1000000.0) + " ms.");
    }
    public static void test() {
        aroundTime += testAround();
        inTime += testIn();
    }
    public static long testIn() {
        long start = System.nanoTime();
        Integer i = tryInLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static long testAround() {
        long start = System.nanoTime();
        Integer i = tryAroundLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static Integer tryInLoop() {
        int count = 0;
        for (int i = 0; i < ITERATIONS; i++) {
            try {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            } catch (NumberFormatException ex) {
                return null;
            }
        }
        return count;
    }
    public static Integer tryAroundLoop() {
        int count = 0;
        try {
            for (int i = 0; i < ITERATIONS; i++) {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            }
            return count;
        } catch (NumberFormatException ex) {
            return null;
        }
    }
}

Tôi đã kiểm tra mã byte kết quả bằng cách sử dụng javap để đảm bảo rằng không có gì được nội tuyến.

Kết quả cho thấy, giả sử tối ưu hóa JIT không đáng kể, Jeffrey là chính xác ; hoàn toàn không có sự khác biệt về hiệu năng trên Java 6, máy khách Sun (Tôi không có quyền truy cập vào các phiên bản khác). Tổng thời gian chênh lệch theo thứ tự vài mili giây trong toàn bộ bài kiểm tra.

Do đó, sự cân nhắc duy nhất là những gì trông sạch sẽ nhất. Tôi thấy rằng cách thứ hai là xấu, vì vậy tôi sẽ theo cách thứ nhất hoặc theo cách của Ray Hayes .


Nếu trình xử lý ngoại lệ có dòng chảy bên ngoài vòng lặp, thì tôi cảm thấy rõ ràng nhất là đặt nó bên ngoài vòng lặp - Thay vì đặt một mệnh đề bắt rõ ràng trong vòng lặp, tuy nhiên nó sẽ trả về. Tôi sử dụng một dòng khoảng trắng xung quanh phần thân "bắt" của các phương thức "bắt tất cả" như vậy, để phân tách rõ hơn phần thân khỏi khối thử bao quanh .
Thomas W

16

Mặc dù hiệu suất có thể giống nhau và những gì "có vẻ" tốt hơn là rất chủ quan, vẫn có một sự khác biệt khá lớn về chức năng. Lấy ví dụ sau:

Integer j = 0;
    try {
        while (true) {
            ++j;

            if (j == 20) { throw new Exception(); }
            if (j%4 == 0) { System.out.println(j); }
            if (j == 40) { break; }
        }
    } catch (Exception e) {
        System.out.println("in catch block");
    }

Vòng lặp while nằm trong khối try Catch, biến 'j' được tăng lên cho đến khi nó đạt 40, được in ra khi j mod 4 bằng 0 và một ngoại lệ được ném khi j chạm 20.

Trước bất kỳ chi tiết nào, đây là ví dụ khác:

Integer i = 0;
    while (true) {
        try {
            ++i;

            if (i == 20) { throw new Exception(); }
            if (i%4 == 0) { System.out.println(i); }
            if (i == 40) { break; }

        } catch (Exception e) { System.out.println("in catch block"); }
    }

Cùng một logic như trên, chỉ khác là khối try / Catch hiện nằm trong vòng lặp while.

Ở đây có đầu ra (trong khi thử / bắt):

4
8
12 
16
in catch block

Và đầu ra khác (thử / bắt trong khi):

4
8
12
16
in catch block
24
28
32
36
40

Ở đó bạn có một sự khác biệt đáng kể:

trong khi thử / bắt thoát ra khỏi vòng lặp

thử / bắt trong khi giữ cho vòng lặp hoạt động


Vì vậy, đặt try{} catch() {}xung quanh vòng lặp nếu vòng lặp được coi là một "đơn vị" duy nhất và việc tìm ra một vấn đề trong đơn vị đó làm cho toàn bộ "đơn vị" (hoặc vòng lặp trong trường hợp này) đi về phía nam. Đặt try{} catch() {}bên trong vòng lặp nếu bạn đang xử lý một lần lặp duy nhất của vòng lặp hoặc một phần tử duy nhất trong một mảng dưới dạng toàn bộ "đơn vị". Nếu một ngoại lệ trong "đơn vị" đó xảy ra, chúng ta chỉ cần bỏ qua phần tử đó và sau đó chúng ta tiếp tục đến lần lặp tiếp theo của vòng lặp.
Galaxy

14

Tôi đồng ý với tất cả các bài viết hiệu suất và dễ đọc. Tuy nhiên, có những trường hợp nó thực sự quan trọng. Một vài người khác đã đề cập đến điều này, nhưng có thể dễ thấy hơn với các ví dụ.

Xem xét ví dụ sửa đổi một chút này:

public static void main(String[] args) {
    String[] myNumberStrings = new String[] {"1.2345", "asdf", "2.3456"};
    ArrayList asNumbers = parseAll(myNumberStrings);
}

public static ArrayList parseAll(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        myFloats.add(new Float(numberStrings[i]));
    }
    return myFloats;
}

Nếu bạn muốn phương thức parseAll () trả về null nếu có bất kỳ lỗi nào (như ví dụ ban đầu), bạn sẽ đặt thử / bắt ở bên ngoài như thế này:

public static ArrayList parseAll1(String[] numberStrings){
    ArrayList myFloats = new ArrayList();
    try{
        for(int i = 0; i < numberStrings.length; i++){
            myFloats.add(new Float(numberStrings[i]));
        }
    } catch (NumberFormatException nfe){
        //fail on any error
        return null;
    }
    return myFloats;
}

Trong thực tế, có lẽ bạn nên trả về một lỗi ở đây thay vì null và nói chung tôi không thích có nhiều trả về, nhưng bạn hiểu ý.

Mặt khác, nếu bạn muốn nó bỏ qua các vấn đề và phân tích bất kỳ chuỗi nào có thể, bạn sẽ đặt thử / bắt vào bên trong vòng lặp như thế này:

public static ArrayList parseAll2(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        try{
            myFloats.add(new Float(numberStrings[i]));
        } catch (NumberFormatException nfe){
            //don't add just this one
        }
    }

    return myFloats;
}

2
Đó là lý do tại sao tôi nói "Nếu bạn chỉ đơn giản muốn bắt một giá trị xấu nhưng tiếp tục xử lý, hãy đặt nó vào trong."
Ray Hayes

5

Như đã đề cập, hiệu suất là như nhau. Tuy nhiên, trải nghiệm người dùng không nhất thiết phải giống hệt nhau. Trong trường hợp đầu tiên, bạn sẽ thất bại nhanh (tức là sau lỗi đầu tiên), tuy nhiên nếu bạn đặt khối try / Catch bên trong vòng lặp, bạn có thể nắm bắt tất cả các lỗi sẽ được tạo cho một cuộc gọi cho phương thức đã cho. Khi phân tích một mảng các giá trị từ các chuỗi mà bạn mong đợi một số lỗi định dạng, chắc chắn có trường hợp bạn muốn có thể trình bày tất cả các lỗi cho người dùng để họ không cần phải thử và sửa từng lỗi một .


Điều này không đúng với trường hợp cụ thể này (tôi đang trở lại trong khối bắt), nhưng nói chung là một điều tốt để ghi nhớ.
Michael Myers

4

Nếu tất cả hoặc không có gì thất bại, thì định dạng đầu tiên có ý nghĩa. Nếu bạn muốn có thể xử lý / trả về tất cả các phần tử không bị lỗi, bạn cần sử dụng biểu mẫu thứ hai. Đó sẽ là những tiêu chí cơ bản của tôi để lựa chọn giữa các phương pháp. Cá nhân, nếu nó là tất cả hoặc không có gì, tôi sẽ không sử dụng hình thức thứ hai.


4

Miễn là bạn nhận thức được những gì bạn cần thực hiện trong vòng lặp, bạn có thể đặt thử bắt bên ngoài vòng lặp. Nhưng điều quan trọng là phải hiểu rằng vòng lặp sau đó sẽ kết thúc ngay khi ngoại lệ xảy ra và đó có thể không phải lúc nào cũng là điều bạn muốn. Đây thực sự là một lỗi rất phổ biến trong phần mềm dựa trên Java. Mọi người cần xử lý một số mục, chẳng hạn như làm trống hàng đợi và dựa vào câu lệnh thử / bắt bên ngoài xử lý tất cả các ngoại lệ có thể xảy ra. Họ cũng có thể chỉ xử lý một ngoại lệ cụ thể trong vòng lặp và không mong đợi bất kỳ ngoại lệ nào khác xảy ra. Sau đó, nếu một ngoại lệ xảy ra không được xử lý bên trong vòng lặp thì vòng lặp sẽ được "định trước", nó sẽ kết thúc sớm và câu lệnh bắt bên ngoài xử lý ngoại lệ đó.

Nếu vòng lặp có vai trò của nó trong cuộc sống để làm trống một hàng đợi thì vòng lặp đó rất có thể có thể kết thúc trước khi hàng đợi đó thực sự bị bỏ trống. Lỗi rất phổ biến.


2

Trong ví dụ của bạn không có sự khác biệt về chức năng. Tôi thấy ví dụ đầu tiên của bạn dễ đọc hơn.


2

Bạn nên thích phiên bản bên ngoài hơn phiên bản bên trong. Đây chỉ là một phiên bản cụ thể của quy tắc, di chuyển bất cứ thứ gì bên ngoài vòng lặp mà bạn có thể di chuyển ra ngoài vòng lặp. Tùy thuộc vào trình biên dịch IL và trình biên dịch JIT, hai phiên bản của bạn có thể có hoặc không có các đặc tính hiệu suất khác nhau.

Trên một lưu ý khác, có lẽ bạn nên xem float.TryPude hoặc Convert.ToFloat.


2

Nếu bạn đặt thử / bắt bên trong vòng lặp, bạn sẽ tiếp tục lặp lại sau một ngoại lệ. Nếu bạn đặt nó bên ngoài vòng lặp, bạn sẽ dừng lại ngay khi ném ngoại lệ.


Chà, tôi sẽ trả về null ngoại lệ, vì vậy nó sẽ không tiếp tục xử lý trong trường hợp của tôi.
Michael Myers

2

Quan điểm của tôi sẽ là các khối thử / bắt là cần thiết để đảm bảo xử lý ngoại lệ phù hợp, nhưng việc tạo các khối như vậy có ý nghĩa về hiệu suất. Vì, các vòng lặp chứa các tính toán lặp đi lặp lại chuyên sâu, không nên đặt các khối thử / bắt trong các vòng lặp. Ngoài ra, có vẻ như tình trạng này xảy ra, nó thường là "Ngoại lệ" hoặc "RuntimeException" bị bắt. RuntimeException bị bắt trong mã nên tránh. Một lần nữa, nếu bạn làm việc trong một công ty lớn, điều cần thiết là phải ghi lại ngoại lệ đó một cách chính xác hoặc ngăn chặn ngoại lệ thời gian chạy xảy ra. Toàn bộ điểm của mô tả này làPLEASE AVOID USING TRY-CATCH BLOCKS IN LOOPS


1

thiết lập khung ngăn xếp đặc biệt cho thử / bắt thêm chi phí bổ sung, nhưng JVM có thể phát hiện ra thực tế là bạn đang quay lại và tối ưu hóa điều này.

tùy thuộc vào số lần lặp, hiệu suất có thể sẽ không đáng kể.

Tuy nhiên tôi đồng ý với những người khác rằng có nó bên ngoài vòng lặp làm cho thân vòng lặp trông gọn gàng hơn.

Nếu có cơ hội bạn sẽ muốn tiếp tục xử lý thay vì thoát nếu có số không hợp lệ, thì bạn sẽ muốn mã nằm trong vòng lặp.


1

Nếu nó ở bên trong, thì bạn sẽ có được chi phí hoạt động của cấu trúc thử / bắt N lần, trái ngược với chỉ một lần ở bên ngoài.


Mỗi khi cấu trúc Thử / Bắt được gọi, nó sẽ thêm chi phí cho việc thực thi phương thức. Chỉ cần một chút bộ nhớ và bộ xử lý cần thiết để xử lý cấu trúc. Nếu bạn đang chạy một vòng lặp 100 lần và vì lợi ích giả định, giả sử chi phí là 1 tick cho mỗi cuộc gọi thử / bắt, thì việc thử / Bắt trong vòng lặp sẽ khiến bạn mất 100 tick, thay vì chỉ 1 tick nếu đó là bên ngoài vòng lặp.


Bạn có thể xây dựng một chút trên đầu?
Michael Myers

1
Được rồi, nhưng Jeffrey L Whitledge nói rằng không có thêm chi phí. Bạn có thể cung cấp một nguồn nói rằng có?
Michael Myers

Chi phí nhỏ, hầu như không đáng kể, nhưng nó ở đó - mọi thứ đều có chi phí. Dưới đây là một bài viết blog từ Programmer của Thiên Đàng ( tiny.cc/ZBX1b ) liên quan .NET và đây là một bài nhóm tin từ Reshat Sabiq liên quan đến JAVA ( tiny.cc/BV2hS )
Stephen Wrighton

Tôi hiểu rồi ... Vì vậy, bây giờ câu hỏi là, chi phí phát sinh khi thử / bắt (trong trường hợp đó phải ở ngoài vòng lặp), hay nó không đổi trong suốt thời gian thử / bắt (trong trường hợp đó là nên ở trong vòng lặp)? Bạn nói đó là số 1. Và tôi vẫn chưa hoàn toàn thuyết phục có một chi phí.
Michael Myers

1
Theo Google Book này ( tinyurl.com/3pp7qj ), "các máy ảo mới nhất không bị phạt".
Michael Myers

1

Toàn bộ quan điểm của các trường hợp ngoại lệ là khuyến khích kiểu đầu tiên: cho phép xử lý lỗi được hợp nhất và xử lý một lần, không phải ngay lập tức tại mọi trang web lỗi có thể.


Sai lầm! Điểm của các trường hợp ngoại lệ là xác định hành vi đặc biệt nào sẽ áp dụng khi xảy ra "lỗi". Do đó, việc chọn khối thử / bắt bên trong hoặc bên ngoài thực sự phụ thuộc vào cách bạn muốn xử lý vòng điều trị.
gizmo

Điều đó có thể được thực hiện tốt như nhau với các phương pháp xử lý lỗi ngoại lệ, chẳng hạn như chuyển các cờ "lỗi xảy ra" xung quanh.
wnoise

1

đưa nó vào trong. Bạn có thể tiếp tục xử lý (nếu bạn muốn) hoặc bạn có thể đưa ra một ngoại lệ hữu ích cho khách hàng biết giá trị của myString và chỉ mục của mảng chứa giá trị xấu. Tôi nghĩ NumberFormatException sẽ cho bạn biết giá trị xấu nhưng nguyên tắc là đặt tất cả dữ liệu hữu ích trong các ngoại lệ mà bạn ném. Hãy suy nghĩ về những gì sẽ thú vị với bạn trong trình gỡ lỗi tại thời điểm này trong chương trình.

Xem xét:

try {
   // parse
} catch (NumberFormatException nfe){
   throw new RuntimeException("Could not parse as a Float: [" + myString + 
                              "] found at index: " + i, nfe);
} 

Trong lúc cần thiết, bạn sẽ thực sự đánh giá cao một ngoại lệ như thế này với càng nhiều thông tin trong đó càng tốt.


Vâng, đây cũng là một điểm hợp lệ. Trong trường hợp của tôi, tôi đang đọc từ một tập tin, vì vậy tất cả những gì tôi thực sự cần là chuỗi không thể phân tích cú pháp. Vì vậy, tôi đã làm System.out.println (ví dụ) thay vì ném một ngoại lệ khác (tôi muốn phân tích càng nhiều tệp càng hợp pháp).
Michael Myers

1

Tôi muốn thêm ý kiến ​​riêng của mình 0.02cvề hai cân nhắc cạnh tranh khi xem xét vấn đề chung về vị trí xử lý ngoại lệ:

  1. Trách nhiệm của " try-catchkhối " rộng hơn (nghĩa là bên ngoài vòng lặp trong trường hợp của bạn) có nghĩa là khi thay đổi mã tại một số điểm sau đó, bạn có thể thêm nhầm một dòng được xử lý bởi catchkhối hiện có của bạn ; có thể vô tình Trong trường hợp của bạn, điều này ít xảy ra vì bạn rõ ràng đang bắtNumberFormatException

  2. "Thu hẹp" trách nhiệm của try-catchkhối, việc tái cấu trúc càng khó khăn hơn. Đặc biệt là khi (như trong trường hợp của bạn) bạn đang thực hiện một lệnh "không cục bộ" từ trong catchkhối ( return nullcâu lệnh).


1

Điều đó phụ thuộc vào việc xử lý thất bại. Nếu bạn chỉ muốn bỏ qua các yếu tố lỗi, hãy thử bên trong:

for(int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    } catch (NumberFormatException ex) {
        --i;
    }
}

Trong mọi trường hợp khác, tôi muốn thử bên ngoài. Mã dễ đọc hơn, sạch sẽ hơn. Có lẽ sẽ tốt hơn nếu ném IllegalArgumentException trong trường hợp lỗi thay vì trả về null.


1

Tôi sẽ đưa 0,02 đô la của mình vào. Đôi khi, bạn cần phải thêm "cuối cùng" vào mã của mình (vì ai đã từng viết mã của họ một cách hoàn hảo ngay lần đầu tiên?). Trong những trường hợp đó, đột nhiên sẽ có ý nghĩa hơn khi thử / bắt bên ngoài vòng lặp. Ví dụ:

try {
    for(int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        dbConnection.update("MY_FLOATS","INDEX",i,"VALUE",myNum);
    }
} catch (NumberFormatException ex) {
    return null;
} finally {
    dbConnection.release();  // Always release DB connection, even if transaction fails.
}

Bởi vì nếu bạn gặp lỗi hoặc không, bạn chỉ muốn giải phóng kết nối cơ sở dữ liệu của mình (hoặc chọn loại tài nguyên khác yêu thích của bạn ...) một lần.


1

Một khía cạnh khác không được đề cập ở trên là thực tế là mọi lần thử bắt đều có một số tác động đến ngăn xếp, điều này có thể có ý nghĩa đối với các phương pháp đệ quy.

Nếu phương thức "bên ngoài ()" gọi phương thức "bên trong ()" (có thể tự gọi đệ quy), hãy thử xác định vị trí thử bắt trong phương thức "bên ngoài ()" nếu có thể. Một ví dụ "stack stack" đơn giản mà chúng ta sử dụng trong lớp hiệu suất không thành công ở khoảng 6.400 khung hình khi bắt thử ở phương thức bên trong và ở khoảng 11.600 khi nó ở phương thức bên ngoài.

Trong thế giới thực, đây có thể là một vấn đề nếu bạn đang sử dụng mẫu Tổng hợp và có các cấu trúc lồng nhau lớn, phức tạp.


0

Nếu bạn muốn bắt Ngoại lệ cho mỗi lần lặp hoặc kiểm tra xem Lặp lại ngoại lệ nào được ném và bắt mọi Ngoại lệ trong một lần lặp, hãy thử ... bắt trong vòng lặp. Điều này sẽ không phá vỡ vòng lặp nếu Ngoại lệ xảy ra và bạn có thể bắt mọi Ngoại lệ trong mỗi lần lặp trong suốt vòng lặp.

Nếu bạn muốn phá vỡ vòng lặp và kiểm tra Ngoại lệ bất cứ khi nào bị ném, hãy sử dụng thử ... thoát khỏi vòng lặp. Điều này sẽ phá vỡ vòng lặp và thực hiện các câu lệnh sau khi bắt (nếu có).

Tất cả phụ thuộc vào nhu cầu của bạn. Tôi thích sử dụng thử ... bắt bên trong vòng lặp trong khi triển khai vì nếu Ngoại lệ xảy ra, kết quả không mơ hồ và vòng lặp sẽ không phá vỡ và thực thi hoàn toàn.

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.