2012-06-09 36 views
27

Nếu tôi không nhầm, các lớp con của Ngoại lệ phải được bắt trước. Nhưng phải nắm bắt bất kỳ RuntimeException và một ngoại lệ kiểm tra cụ thể, mà nên được đánh bắt lúc đầu?Thứ tự bắt ngoại lệ trong Java

try { 
    ... 
} catch(RuntimeException e) { 
    ... 
} catch(IOException e) { 
    ... 
} 

Thứ tự này có đúng không? Hoặc là nó đúng nhưng một lựa chọn xấu?

Trả lời

49

Thứ tự là bất kỳ thứ gì khớp trước, được thực hiện (as the JLS clearly explains).

Nếu lần bắt đầu khớp với ngoại lệ, nó sẽ thực hiện, nếu nó không khớp, lệnh tiếp theo sẽ được thử và bật cho đến khi một kết quả khớp hoặc không có.

Vì vậy, khi bắt ngoại lệ, bạn muốn luôn bắt đầu cụ thể nhất trước và sau đó là chung nhất (như RuntimeException hoặc Ngoại lệ). Ví dụ, hãy tưởng tượng bạn muốn để bắt StringIndexOutOfBoundsException ném theo phương pháp String.charAt(index) nhưng mã của bạn cũng có thể ném một NullPointerException, dưới đây là cách bạn có thể đi để bắt các ngoại lệ:

String s = null; 
try { 
    s.charAt(10); 
} catch (NullPointerExeption e) { 
    System.out.println("null"); 
    e.printStackTrace(); 
} catch (StringIndexOutOfBoundsException e) { 
    System.out.println("String index error!"); 
    e.printStackTrace(); 
} catch (RuntimeException e) { 
    System.out.println("runtime exception!"); 
    e.printStackTrace(); 
} 

Như vậy, với lệnh này, Tôi đảm bảo rằng các ngoại lệ được bắt chính xác và chúng không bị vấp ngã lẫn nhau, nếu đó là một số NullPointerException nó đi vào lần bắt đầu tiên, nếu StringIndexOutOfBoundsException nó đi vào thứ hai và cuối cùng nếu nó là cái gì đó khác là RuntimeException (hoặc thừa kế từ nó, như một số IllegalArgumentException) nó đi vào bắt thứ ba.

Trường hợp của bạn là chính xác như IOException thừa kế từ Ngoại lệ và RuntimeException cũng được thừa hưởng từ Ngoại lệ, do đó, chúng sẽ không đi qua nhau.

Nó cũng là một lỗi biên dịch để đón một ngoại lệ chung đầu tiên và sau đó một trong đó là con cháu sau này, như trong:

try { 
    // some code here 
} catch (Exception e) { 
    e.printStackTrace(); 
} catch (RuntimeException e) { // this line will cause a compilation error because it would never be executed since the first catch would pick the exception 
    e.printStackTrace(); 
} 

Vì vậy, bạn nên có những đứa trẻ đầu tiên và sau đó là trường hợp ngoại lệ cha mẹ.

+0

'Muốn' không liên quan gì đến nó. Trình biên dịch thực thi đúng thứ tự. – EJP

1

Bất kỳ thứ tự nào trình biên dịch sẽ chấp nhận là chính xác.

+0

@downvoter Giải thích xin vui lòng. Không có lỗi ở đây. Cả hai câu trả lời khác đều đồng ý. Nếu bạn không đồng ý, hãy làm điều đó một cách rõ ràng, nhưng hãy chuẩn bị để trích dẫn chương và câu. – EJP

4

Đơn đặt hàng này có đúng không? Hoặc là nó đúng nhưng một lựa chọn xấu?

Không. Như các câu trả lời khác đã nói, trình biên dịch sẽ cho bạn biết nếu bạn đặt các đánh bắt đơn giản theo thứ tự trong đó một mặt nạ khác.

Nhưng có một vấn đề khác có thể xảy ra trong mã của bạn: bạn có thực sự bắt được RuntimeException hay không. Vấn đề là có nhiều nguồn/nguyên nhân của các ngoại lệ uunchecked, và nhiều nguồn/nguyên nhân đó thực sự là lỗi trong ứng dụng của bạn.

Sử dụng catch để đăng nhập một chẩn đoán như là một phần của một tắt máy khẩn cấp là tốt, nhưng nếu bạn bắt và cố gắng để phục hồi từRuntimeException, bạn cần phải cẩn thận rằng bạn không quét một vấn đề nghiêm trọng dưới thảm :

  • Đảm bảo bạn đăng nhập ngoại lệ và ngăn xếp của nó, bất kể là gì.

  • Hãy xem xét liệu có phải là khôn ngoan để cố gắng khôi phục. Nếu bạn đã có một lỗi không xác định, nó có thể đã thực hiện thiệt hại không thể đoán trước trước khi kích hoạt ngoại lệ. Bạn không có cách nào để biết liệu ứng dụng có thể phục hồi hay không hoặc liệu nó có thể gây ra thiệt hại tồi tệ hơn bằng cách cố gắng tiếp tục hay không.

Lời khuyên này cũng áp dụng để bắt ExceptionThrowable/Error. Và nó quan trọng hơn với Throwable/Error vì bản chất của sát thương có thể đã xảy ra.

+0

Đó là một điểm tốt. Nhưng những gì bạn có nghĩa là nói "và cố gắng để phục hồi từ RuntimeException"? Tôi đã không cố gắng làm điều đó, thực sự người ta không cần phải phục hồi từ RuntimeException. Hay không? –

+0

Bằng cách "cố gắng khôi phục", tôi có nghĩa là làm điều gì khác ngoài việc cho phép hoặc khiến ứng dụng thoát. Không rõ liệu mã của bạn có thực hiện điều đó hay không. (Nó phụ thuộc vào những gì xảy ra trong mã kèm theo.) Dù sao tôi không nói rằng bạn * làm * làm điều này. Thay vào đó, tôi cung cấp lời khuyên chung áp dụng bất cứ khi nào mã của bạn bắt được một trong các lớp ngoại lệ gốc. –

+0

Ồ, tôi hiểu rồi, cảm ơn. –