2010-09-23 27 views
112

Trên một câu hỏi dành cho Java tại trường đại học, đã có đoạn mã này:ngoại lệ ném vào đánh bắt và cuối cùng khoản

class MyExc1 extends Exception {} 
class MyExc2 extends Exception {} 
class MyExc3 extends MyExc2 {} 

public class C1 { 
    public static void main(String[] args) throws Exception { 
     try { 
      System.out.print(1); 
      q(); 
     } 
     catch (Exception i) { 
      throw new MyExc2(); 
     } 
     finally { 
      System.out.print(2); 
      throw new MyExc1(); 
     } 
    } 

    static void q() throws Exception { 
     try { 
      throw new MyExc1(); 
     } 
     catch (Exception y) { 
     } 
     finally { 
      System.out.print(3); 
      throw new Exception(); 
     } 
    } 
} 

Tôi đã yêu cầu cung cấp sản lượng của nó. Tôi đã trả lời 13Exception in thread main MyExc2, nhưng câu trả lời đúng là 132Exception in thread main MyExc1. Tại sao? Tôi chỉ không thể hiểu được MyExc2 đi đâu.

Trả lời

112

Dựa trên đọc câu trả lời của bạn và nhìn thấy làm thế nào bạn có thể nghĩ ra nó, tôi tin rằng bạn nghĩ rằng một "ngoại lệ-tiến bộ" có "ưu tiên". Lưu ý:

Khi một ngoại lệ mới được ném trong một khối bắt hoặc khối finally đó sẽ tuyên truyền ra khỏi khối đó, sau đó ngoại trừ hiện tại sẽ được hủy bỏ (và quên) là ngoại lệ mới được lan truyền ra bên ngoài . Ngoại lệ mới bắt đầu giải phóng ngăn xếp giống như bất kỳ ngoại lệ nào khác, hủy bỏ khỏi khối hiện tại (khối catch hoặc cuối cùng) và tùy thuộc vào bất kỳ bắt ứng dụng nào hoặc cuối cùng là chặn trên đường đi.

Lưu ý rằng bắt được áp dụng hoặc cuối cùng khối bao gồm:

Khi một ngoại lệ mới được ném trong một khối catch, ngoại lệ mới là vẫn tuân theo mà bắt của khối finally, nếu có.

Bây giờ, hãy nhớ lại việc thực hiện ghi nhớ rằng, bất cứ khi nào bạn nhấn throw, bạn nên hủy theo dõi ngoại lệ hiện tại và bắt đầu theo dõi ngoại lệ mới.

+5

«Dựa trên việc đọc câu trả lời của bạn và thấy cách bạn có thể nghĩ ra, tôi tin rằng bạn nghĩ rằng" ngoại lệ "có" ưu tiên "» Cảm ơn bạn ... đó là suy nghĩ của tôi :) – JustB

0

Tôi nghĩ rằng bạn chỉ cần đi bộ finally khối:

  1. Print "1".
  2. finally in q in "3".
  3. finally in main in "2".
17

Điều khoản cuối cùng được thực hiện ngay cả khi ngoại lệ được ném từ bất kỳ nơi nào trong khối try/catch.

Vì đó là lần cuối cùng được thực hiện trong main và nó ném một ngoại lệ, đó là ngoại lệ mà người gọi thấy.

Do đó, tầm quan trọng của việc đảm bảo rằng mệnh đề finally không ném bất kỳ điều gì, vì nó có thể nuốt ngoại lệ từ khối try.

+3

Nó cũng sẽ được thực hiện ngay cả khi không có ngoại lệ ném vào khối try/catch – nanda

+2

1: trực tiếp và đến điểm mà không uốn cong xuống toàn bộ ngăn xếp mà OP đã xuất hiện để hiểu. – Powerlord

33

Đây là những gì Wikipedia nói về khoản cuối cùng:

Phổ biến hơn là một điều khoản liên quan (cuối cùng, hoặc bảo đảm) sẽ được thực thi dù một ngoại lệ xảy ra hay không, thường để giải phóng nguồn lực mua trong phần nội dung của khối xử lý ngoại lệ .

Hãy chia nhỏ chương trình của bạn.

try { 
    System.out.print(1); 
    q(); 
} 

Vì vậy, 1 sẽ được xuất vào màn hình, sau đó gọi là q(). Trong q(), một ngoại lệ được ném. Ngoại lệ sau đó bị bắt bởi Exception y nhưng không có gì. Sau đó, điều khoản cuối cùng là sẽ được thực thi (nó phải), vì vậy, 3 sẽ được in ra màn hình. Bởi vì (trong phương pháp q() có một ngoại lệ ném trong mệnh đề cuối cùng, cũng q() phương pháp vượt qua ngoại lệ đối với chồng mẹ (bởi throws Exception trong tờ khai phương pháp) new Exception() sẽ được ném và đánh bắt bằng catch (Exception i), MyExc2 ngoại lệ sẽ được ném (bây giờ thêm nó vào ngoại lệ stack), nhưng một cuối cùng trong khối main sẽ được thực hiện đầu tiên.

vì vậy, trong,

catch (Exception i) { 
    throw(new MyExc2()); 
} 
finally { 
    System.out.print(2); 
    throw(new MyExc1()); 
} 

một cuối cùng mệnh đề được gọi là ... (hãy nhớ, chúng tôi vừa mới bắt được Exception i và ném MyExc2) về bản chất, 2 được in trên màn hình ...và sau khi 2 được in trên màn hình, một ngoại lệ MyExc1 được ném. MyExc1 được xử lý theo phương pháp public static void main(...).

Output:

"132Exception trong MyExc1 chính chủ đề"

Giảng viên là chính xác! :-)

Về bản chất, nếu bạn có một cuối cùng trong mệnh đề try/catch, một cuối cùng sẽ được thực hiện (sau bắt ngoại trừ trước ném ngoại lệ bắt ra)

+0

'catch' được thực hiện vì' q() 'đã ném một' Exception' từ khối 'finally' của chính nó. –

+0

"Trong q(), một ngoại lệ được ném nhưng trước khi ngoại lệ được ném hoàn toàn, một mệnh đề cuối cùng được thực thi đầu tiên, vì vậy, 3 sẽ được in ra màn hình." Er ... không, ngoại lệ đầu tiên được ném vào 'q' chuyển thực thi đến khối 'catch' rỗng trong' q' (mà nuốt ngoại lệ này), sau đó đến khối 'finally' trong' q'. Nói cuối cùng là chặn các bản in '3', sau đó ném một ngoại lệ mới, nhờ vào' q''s 'throws Exception' được chuyển lên ngăn xếp cho phụ huynh. – Powerlord

6

Một method không thể throw hai trường hợp ngoại lệ cùng một lúc. Nó sẽ luôn ném ném cuối cùng exception, mà trong trường hợp này nó sẽ luôn luôn là một trong những từ khối finally.

Khi ngoại lệ đầu tiên từ phương pháp q() được ném, nó sẽ bị bắt và sau đó được nuốt bởi khối ngoại lệ cuối cùng bị ném.

q() -> ném new Exception->maincatch Exception->thrownew Exception->finally ném một mới exception (và một từ catch là "mất")

2

Cách dễ nhất để nghĩ về điều này là hãy tưởng tượng rằng có một biến toàn cầu cho toàn bộ ứng dụng đang giữ ngoại lệ hiện tại.

Exception currentException = null; 

Khi mỗi ngoại lệ được ném, "currentException" được đặt thành ngoại lệ đó. Khi ứng dụng kết thúc, nếu currentException là! = Null, thì thời gian chạy báo cáo lỗi.

Ngoài ra, các khối cuối cùng luôn chạy trước khi thoát khỏi phương thức. Sau đó bạn có thể bù lại đoạn mã vào:

public class C1 { 

    public static void main(String [] argv) throws Exception { 
     try { 
      System.out.print(1); 
      q(); 

     } 
     catch (Exception i) { 
      // <-- currentException = Exception, as thrown by q()'s finally block 
      throw(new MyExc2()); // <-- currentException = MyExc2 
     } 
     finally { 
      // <-- currentException = MyExc2, thrown from main()'s catch block 
      System.out.print(2); 
      throw(new MyExc1()); // <-- currentException = MyExc1 
     } 

    } // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console. 

    static void q() throws Exception { 
     try { 
      throw(new MyExc1()); // <-- currentException = MyExc1 
     } 
     catch(Exception y) { 
      // <-- currentException = null, because the exception is caught and not rethrown 
     } 
     finally { 
      System.out.print(3); 
      throw(new Exception()); // <-- currentException = Exception 
     } 
    } 
} 

Thứ tự mà các ứng dụng thực hiện là:

main() 
{ 
    try 
    q() 
    { 
     try 
     catch 
     finally 
    } 
    catch 
    finally 
} 
-1

Tôi nghĩ rằng đây giải quyết vấn đề:

boolean allOk = false; 
try{ 
    q(); 
    allOk = true; 
} finally { 
    try { 
    is.close(); 
    } catch (Exception e) { 
    if(allOk) { 
     throw new SomeException(e); 
    } 
    } 
} 
+3

Vấn đề là gì bạn sẽ "giải quyết"? Bạn có nghĩa là câu hỏi trong kỳ thi? nó đã được trả lời rồi. Nếu bạn có nghĩa là vấn đề của các mã nhất định, vì nó chỉ là một câu hỏi thi không có ý nghĩa để đổ lỗi cho nó ra. –

1

Nó cũng được biết rằng khối cuối cùng được thực hiện sau khi thử và nắm bắt và luôn thực hiện .... Nhưng như bạn đã thấy đó là một chút đôi chút khôn lanh đôi khi kiểm tra những đoạn mã dưới đây và bạn sẽ rằng câu trả lời và ném không luôn luôn làm những gì họ nên làm theo thứ tự mà chúng ta mong đợi chủ đề.

Chúc mừng.

/////////////Return dont always return/////// 

try{ 

    return "In Try"; 

} 

finally{ 

    return "In Finally"; 

} 

//////////////////////////////////////////// 


////////////////////////////////////////////  
while(true) { 

    try { 

     return "In try"; 

    } 

    finally{ 

     break;  

    }   
}    
return "Out of try";  
/////////////////////////////////////////// 


/////////////////////////////////////////////////// 

while (true) {  

    try {    

     return "In try";  

    } 
    finally { 

     continue; 

    }       
} 
////////////////////////////////////////////////// 

/////////////////Throw dont always throw///////// 

try { 

    throw new RuntimeException(); 

} 
finally { 

    return "Ouuuups no throw!"; 

} 
////////////////////////////////////////////////// 
25

Trích dẫn từ JLS 9: 14.20.2. Execution of try-finally and try-catch-finally

Nếu khối catch hoàn đột ngột vì lý do R, sau đó khối cuối cùng được thực thi. Sau đó, có một sự lựa chọn:

  • Nếu khối cuối cùng hoàn thành bình thường, sau đó báo cáo kết quả thử hoàn đột ngột vì lý do R.

  • Nếu khối cuối cùng hoàn thành đột ngột vì lý do S, sau đó báo cáo kết quả thử hoàn thành đột ngột vì lý do S (và lý do R bị loại bỏ).

0
class MyExc1 extends Exception {} 
class MyExc2 extends Exception {} 
class MyExc3 extends MyExc2 {} 

public class C1 { 
    public static void main(String[] args) throws Exception { 
     try { 
      System.out.print("TryA L1\n"); 
      q(); 
      System.out.print("TryB L1\n"); 
     } 
     catch (Exception i) { 
      System.out.print("Catch L1\n");     
     } 
     finally { 
      System.out.print("Finally L1\n"); 
      throw new MyExc1(); 
     } 
    } 

    static void q() throws Exception { 
     try { 
      System.out.print("TryA L2\n"); 
      q2(); 
      System.out.print("TryB L2\n"); 
     } 
     catch (Exception y) { 
      System.out.print("Catch L2\n"); 
      throw new MyExc2(); 
     } 
     finally { 
      System.out.print("Finally L2\n"); 
      throw new Exception(); 
     } 
    } 

    static void q2() throws Exception { 
     throw new MyExc1(); 
    } 
} 

thứ tự:

TryA L1 
TryA L2 
Catch L2 
Finally L2 
Catch L1 
Finally L1   
Exception in thread "main" MyExc1 at C1.main(C1.java:30) 

https://www.compilejava.net/

+1

Mặc dù đoạn mã này có thể là giải pháp, bao gồm giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho người đọc trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn –

Các vấn đề liên quan