Câu hỏi Phá vỡ vòng lặp lồng nhau trong Java


Tôi đã có một vòng lặp lồng nhau xây dựng như thế này:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             break; // Breaks out of the inner loop
         }
    }
}

Bây giờ làm thế nào tôi có thể thoát ra khỏi cả hai vòng. Tôi đã xem xét các câu hỏi tương tự, nhưng không có vấn đề gì liên quan đến Java. Tôi không thể áp dụng các giải pháp này vì hầu hết các ảnh được sử dụng.

Tôi không muốn đặt vòng lặp bên trong theo một phương pháp khác.

Cập nhật: Tôi không muốn chạy lại các vòng lặp, khi phá vỡ tôi đã hoàn thành với việc thực hiện khối vòng lặp.


1542
2018-05-20 09:07


gốc




Các câu trả lời:


Giống như những người trả lời khác, tôi chắc chắn thích hơn để đặt vòng lặp bên trong theo một phương pháp khác. Câu trả lời này chỉ cho thấy các yêu cầu trong câu hỏi có thể được đáp ứng như thế nào.

Bạn có thể dùng break với nhãn cho vòng lặp ngoài. Ví dụ:

public class Test {
    public static void main(String[] args) {
        outerloop:
        for (int i=0; i < 5; i++) {
            for (int j=0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    break outerloop;
                }
                System.out.println(i + " " + j);
            }
        }
        System.out.println("Done");
    }
}

Bản in này:

0 0
0 1
0 2
0 3
0 4
1 0
1 1
1 2
1 3
1 4
2 0
2 1
2 2
2 3
Breaking
Done

2084
2018-05-20 09:11



Điều này làm nhảy trực tiếp sau vòng lặp. Thử nó! Có, nhãn sẽ xuất hiện trước vòng lặp, nhưng đó là vì nhãn này gắn nhãn vòng lặp thay vì địa điểm bạn muốn thoát. (Bạn cũng có thể tiếp tục với một nhãn.) - Jon Skeet
Perl cũng cho phép hệ thống nhãn hiệu riêng của mình. Tôi nghĩ rằng rất nhiều ngôn ngữ làm - nó hầu như không làm tôi ngạc nhiên rằng nó là trong Java. - Evan Carroll
@Evan - tuyên bố đó rõ ràng là đúng - bằng các ngôn ngữ hứa hẹn rằng đó là sự thật. Nhưng Java không thực hiện lời hứa đó. Nếu một ngôn ngữ xung đột với các giả định của bạn, có thể đó là các giả định của bạn có lỗi. Trong trường hợp này, tôi nghĩ bạn vẫn còn một phần đúng - nguyên tắc ít gây bất ngờ nhất cho WRT nhiều người chưa bao giờ nghe nói về (hoặc quên mất) hình thức đó break. Thậm chí sau đó, ngoại lệ là một ngoại lệ nổi tiếng khác (xin lỗi). Nhưng tôi vẫn sẽ không hài lòng về điều này nếu nó không rõ ràng (vòng nhỏ, cảnh báo bình luận nếu nhãn / nghỉ vẫn không nhìn thấy đủ). - Steve314
@ JWiley. Tương tự ở đây; dễ đọc hơn: khi bạn "nhấn" trở lại, bạn có thể ngừng đọc - dễ bảo trì hơn: khi sửa chữa điều gì đó trước khi trả lại, bạn không phải lo lắng về các tác dụng phụ bên ngoài vòng lặp. IMHO, trở về nhanh thường dẫn đến mã nhỏ gọn hơn, đơn giản hơn. - Bruno Grieder
@MuhammadBabar: outerloop là một nhãn. Tôi không biết chính xác mã bạn đã thử, nhưng mã trong câu trả lời của tôi biên dịch và chạy tốt. - Jon Skeet


Về mặt kỹ thuật, câu trả lời đúng là gắn nhãn vòng lặp ngoài. Trong thực tế nếu bạn muốn thoát ra tại bất kỳ điểm nào bên trong một vòng lặp bên trong thì bạn sẽ được tốt hơn off bên ngoài mã vào một phương pháp (một phương pháp tĩnh nếu cần) và sau đó gọi nó.

Điều đó sẽ trả hết cho khả năng đọc.

Mã sẽ trở thành một cái gì đó như thế:

private static String search(...) 
{
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition) {
                // Do something and break...
                return search;
            }
        }
    }
    return null; 
}

Phù hợp với ví dụ cho câu trả lời được chấp nhận:

 public class Test {
    public static void main(String[] args) {
        loop();
        System.out.println("Done");
    }

    public static void loop() {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    return;
                }
                System.out.println(i + " " + j);
            }
        }
    }
}

369
2017-11-14 18:26



Đôi khi bạn sử dụng một số biến địa phương nằm ngoài vòng lặp bên trong, truyền tất cả các biến đó vào có thể cảm thấy bối rối. - Haoest
Vì vậy, làm thế nào là giải pháp này nghĩa vụ phải in "Done" như trong câu trả lời chấp nhận? - JohnDoe
@ JohnDoe bạn gọi nó và sau đó bạn in System.out.println ("done"); thử {} cuối cùng {} trong phương thức tìm kiếm cũng là một tùy chọn. - Zo72
Đây là thực hành tốt hơn tôi đoán, nhưng điều gì sẽ xảy ra nếu bạn muốn tiếp tục thay vì phá vỡ? Nhãn hỗ trợ hoặc là tốt như nhau (hoặc xấu!) Nhưng tôi không chắc chắn làm thế nào để chuyển đổi logic này cho một tiếp tục. - Robert Grant
@RobertGrant Nếu bạn muốn tiếp tục thay vì nghỉ, hãy di chuyển vòng ngoài bên ngoài loop và trở về từ phương thức để tiếp tục. - Muhd


Bạn có thể sử dụng một khối được đặt tên xung quanh các vòng lặp:

search: {
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition) {
                // Do something and break...
                break search;
            }
        }
    }
}

186
2018-05-20 09:12



Bạn không cần phải tạo một khối mới để sử dụng nhãn. - Jon Skeet
Không, nhưng nó làm cho ý định rõ ràng hơn rất nhiều. Xem nhận xét đầu tiên về câu trả lời được chấp nhận. - Bombe
không thực sự là một khối được đặt tên, sau khi nhãn bạn có thể viết bất kỳ biểu thức Java nào mà không có nhãn, name: if(...){...} làm cho điều kiện được đặt tên? :) - La VloZ Merrill


Tôi không bao giờ sử dụng nhãn. Nó có vẻ như là một thực tế xấu để có được vào. Đây là những gì tôi sẽ làm:

boolean finished = false;
for (int i = 0; i < 5 && !finished; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) {
            finished = true;
            break;
        }
    }
}

112
2017-12-07 17:52



Điều này không nên && !finished thay vì || !finished? Và tại sao lại sử dụng break ở tất cả và không sử dụng && !finished cho vòng lặp bên trong quá? - Gandalf
tôi sử dụng break để có thể tự ý thoát khỏi vòng lặp. Nếu có mã sau đó if chặn, bạn có thể break trước khi nó thực hiện. Nhưng bạn nói đúng về &&. Sửa lỗi. - Elle Mundy
giải pháp tốt đẹp! đó là chính xác làm thế nào tôi muốn làm điều đó trong thực tế nếu đặt nó trong một chức năng phụ là không thích hợp hơn vì một lý do nào đó. - benroth
Có một vấn đề tiềm năng nếu có một số logic sau vòng lặp bên trong ... mà sẽ tiếp tục được thực hiện và vòng lặp bên ngoài chỉ bị phá vỡ khi lặp mới bắt đầu ... - Karthik Karuppannan
Tôi không hiểu tại sao người ta nên làm như vậy. Những người làm việc với mã sẽ có thể sử dụng tất cả các tính năng của một ngôn ngữ. Tôi nhận được rằng điều quan trọng là viết mã những người khác có thể hiểu, nhưng không phải bằng cách hạn chế việc sử dụng các công cụ chính thức được cung cấp bởi một ngôn ngữ và tìm cách giải quyết cho cùng một chức năng. Hay bạn có ý gì đó bằng cách "thực hành xấu"? - codepleb


Bạn có thể sử dụng nhãn:

label1: 
for (int i = 0;;) {
    for (int g = 0;;) {
      break label1;
    }
}

79
2018-05-20 09:11



Không công bằng, câu trả lời này cũng đúng. Nhưng chỉ có 55 upvotes .. - WesternGun
Nó cũng đơn giản hơn nhiều để đọc. - dirtysocks45


có thể với một chức năng?

public void doSomething(List<Type> types, List<Type> types2){
  for(Type t1 : types){
    for (Type t : types2) {
      if (some condition) {
         //do something and return...
         return;
      }
    }
  }
}

32
2018-05-20 11:43





Bạn có thể sử dụng biến tạm thời:

boolean outerBreak = false;
for (Type type : types) {
   if(outerBreak) break;
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             outerBreak = true;
             break; // Breaks out of the inner loop
         }
    }
}

Tùy thuộc vào chức năng của bạn, bạn cũng có thể thoát / trả về từ vòng lặp bên trong:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             return;
         }
    }
}

15
2018-05-20 09:11



Tôi thấy kiểu này lộn xộn. - boutta
Vụng về và dễ bị lỗi IMHO. - orbfish
Một điều kiện bổ sung kiểm tra mỗi lần qua vòng lặp? Không, cám ơn. - ryandenki