2013-03-01 22 views
23

tôi phải trả lời câu hỏi này với một số mã:Tại sao có trật tự quan trọng khi bắt ngoại lệ?

Giả sử tôi đã viết các phương pháp kỹ thuật sau:
public void manipulateData () throws java.sql.SQLException, java.sql.SQLDataException

Bạn đang viết mã cho một chương trình cơ sở dữ liệu sẽ sử dụng phương pháp này và bạn muốn xử lý riêng từng số . Điều khoản try/catch trông như thế nào?
Bạn có thể sử dụng no-ops-- các khối trống {} - cho nội dung điều khoản ghi.
Chúng tôi chỉ quan tâm đến cú pháp và cấu trúc của các câu lệnh ở đây.

Tôi đã trả lời với điều này:

try { 

} catch(java.sql.SQLException e) { 

} 
catch(java.sql.SQLDataException e) { 

} 

Ông không chấp nhận câu trả lời vì lý do này:

"mệnh đề catch của bạn là theo thứ tự sai bạn có thể giải thích lý do tại sao những vấn đề trật tự.? "

Anh ấy có đúng trong câu trả lời của mình không?

+4

Một ngoại lệ sẽ chỉ bị bắt một lần. Nếu ngoại lệ đầu tiên phù hợp với loại, thứ hai và như vậy sẽ bị bỏ qua, thậm chí chúng có thể là loại phụ. Vì vậy, các loại phụ bình thường đến đầu tiên và được theo sau bởi các loại siêu, vì vậy các loại ngoại lệ khác nhau sẽ bị bắt chính xác. – shuangwhywhy

+2

Điều này gây ra việc biên dịch ** Mã không thể truy cập là một lỗi **! –

Trả lời

42

Có anh ấy đúng. Như bạn có thể thấy trong số Javadoc, SQLDataException là một phân lớp của SQLException. Do đó, câu trả lời của bạn là sai, vì nó sẽ tạo ra một khối mã không thể truy cập trong số catch thứ hai.

Trong Java, mã này sẽ không biên dịch được. Trong các ngôn ngữ khác (ví dụ: python) mã như vậy sẽ tạo ra một lỗi tinh vi, bởi vì SQLDataException thực sự sẽ bị bắt trong khối đầu tiên, chứ không phải trong phần thứ hai (như trường hợp nếu nó không phải là phân lớp).

Bạn đã trả lời catch(java.sql.SQLException | java.sql.SQLDataException e) { }, nó vẫn sẽ không chính xác, vì câu hỏi yêu cầu xử lý từng ngoại lệ cụ thể.

Câu trả lời đúng là trong Grijesh's answer

+0

nó thực sự là nhiều hơn mà SQLDataException thậm chí sẽ không có sẵn để được bắt tại thời điểm đó, điều này sẽ tạo ra một lỗi nếu tôi nhớ chính xác –

+4

@ ratchetfreak Có. Nếu không thành công tại thời gian biên dịch với 'exception java.sql.SQLDataException đã bị bắt'. Trình biên dịch đủ thông minh để phát hiện điều này. Nhưng ngay cả khi trình biên dịch đã không phát hiện ra nó, nó vẫn sẽ là một lỗi hợp lý, kể từ khi bắt thứ hai sẽ không thể truy cập được. – user000001

+1

Điều này có thể được khái quát hóa với các ngôn ngữ lập trình khác, và trong trường hợp này trình biên dịch có thể không tạo ra lỗi (ví dụ: trong python nơi không thể thực hiện các kiểm tra này tại thời gian biên dịch), và trong trường hợp đó sẽ chỉ có một lỗi. – Bakuriu

22

Trong Java bạn phải đặt ngoại lệ bao gồm ít nhất đầu tiên. Các ngoại lệ tiếp theo phải được bao gồm hơn (khi chúng có liên quan).

Ví dụ: nếu bạn đặt bao gồm tất cả (ngoại lệ) đầu tiên, những cái tiếp theo sẽ không bao giờ được gọi. Mã như sau:

try { 
    System.out.println("Trying to prove a point"); 
    throw new java.sql.SqlDataException("Where will I show up?"); 
}catch(Exception e){ 
    System.out.println("First catch"); 
} catch(java.sql.SQLException e) { 
    System.out.println("Second catch"); 
} 
catch(java.sql.SQLDataException e) { 
    System.out.println("Third catch"); 
} 

sẽ không bao giờ in thư bạn muốn in.

+5

Và trình biên dịch sẽ điên về nó. –

+0

Tuyệt đối. Nhưng câu hỏi thực sự là: liệu người hướng dẫn có còn giận dữ hơn không? – DigCamara

+0

Nếu người hướng dẫn có trình biên dịch trong đầu, nó sẽ là :) –

5

SQLDataException sẽ không bao giờ bị trúng là SQLException sẽ bắt bất kỳ ngoại lệ SQL nào trước khi chúng đạt đến SQLDataException.

SQLDataException là một sub-class của SQLException

5

Hãy nghĩ về phân cấp thừa kế các Ngoại lệ: SQLDataException extends SQLException Vì vậy, nếu bạn bắt 'chung' đầu tiên (tức là cơ sở lớp trên cùng của hệ thống phân cấp) sau đó mọi thứ 'bên dưới' nó có cùng kiểu do sự đa hình tức là, SQLDataExceptionisaSQLException

Vì vậy bạn nên nắm bắt chúng trong từ dưới lên để w.r.t. phân cấp thừa kế nghĩa là, phân lớp đầu tiên tất cả các cách để (chung) lớp cơ sở. Điều này là do các mệnh đề catch được đánh giá theo thứ tự bạn đã khai báo.

+0

nhưng làm cách nào để giải thích phần này nếu câu trả lời của tôi sai? "Bạn có thể giải thích tại sao mệnh lệnh lại quan trọng không?" Anh ấy đang nói về mã của tôi hay chỉ nói về việc sử dụng chung? – user2124033

+0

Cảm ơn thông tin! Đây có phải là cách chính xác để thay đổi ansewr? hãy thử { } bắt (java.sql.SQLException | java.sql.SQLDataException e) { } – user2124033

1

Đối với trình biên dịch nhiều câu lệnh bắt giống như if..else if..else nếu ..

Vì vậy, từ điểm mà trình biên dịch có thể lập bản đồ các ngoại lệ được tạo ra (trực tiếp hoặc bằng cách chuyển đổi kiểu ngầm), nó sẽ không thực thi các phát biểu khai thác tiếp theo.

Để tránh chuyển đổi loại tiềm ẩn này, bạn nên giữ ngoại lệ chung chung hơn. Xuất phát nhiều hơn nên được nêu ở đầu của ông nắm bắt các báo cáo và chung chung nhất nên đi vào các báo cáo khai thác cuối cùng.

SQLDataException có nguồn gốc từ SQLException là thực tập được rút khỏi ngoại lệ. Vì vậy, bạn sẽ không thể thực thi bất kỳ mã nào được viết trong catch(java.sql.SQLDataException e){} khối này. Biên dịch ngay cả cờ cho tình huống đó là mã chết của nó và sẽ không được thực thi.

5

theo thứ tự quan trọng khi bắt ngoại lệ vì lý do sau:

Hãy nhớ rằng:

  • Một cơ sở biến lớp cũng có thể tham khảo đối tượng lớp trẻ.
  • e là một biến tham chiếu
catch(ExceptionType e){ 
} 

Nhân vật chữ thường e là một tham chiếu đến ném (và bị bắt) ExceptionType đối tượng.

Lý do tại sao mã của bạn không được chấp nhận?

Điều quan trọng là hãy nhớ rằng ngoại lệ lớp con phải đến trước khi bất kỳ superclasses của họ. Điều này là do một câu lệnh catch sử dụng một superclasses sẽ bắt ngoại lệ của kiểu đó cộng với bất kỳ các lớp con của nó. Vì vậy, một phân lớp sẽ không bao giờ đạt được nếu nó đến sau siêu lớp của nó.
Hơn nữa, trong Java, Mã không thể truy cập là lỗi.

SQLException là supperclass của SQLDataException

+----+----+----+ 
    | SQLException | `e` can reference SQLException as well as SQLDataException 
    +----+----+----+ 
     ^
      | 
      | 
+----+----+----+---+ 
| SQLDataException | More specific 
+----+----+----+---+ 

Và nếu viết của bạn giống như có lỗi Unreachable code (đọc comments):

try{ 

} 
catch(java.sql.SQLException e){//also catch exception of SQLDataException type 

} 
catch(java.sql.SQLDataException e){//hence this remains Unreachable code 

} 

Nếu bạn thử biên dịch chương trình này, bạn sẽ nhận được thông báo lỗi cho biết rằng câu lệnh catch sẽ xử lý tất cả các lỗi dựa trên SQLException, bao gồm cả SQLDataException.Điều này có nghĩa là câu lệnh bắt thứ hai sẽ không bao giờ thực thi.

Giải pháp đúng?

Để khắc phục nó đảo ngược thứ tự của statements.That bắt được sau:

try{ 

} 
catch(java.sql.SQLDataException e){ 

}catch(java.sql.SQLException e){ 

} 
+0

Tham chiếu: [** Nhiều điều khoản bắt **] (http://aboutjava.net/exception-and-packages /) –

1

Khi ngoại lệ xảy ra trong phương pháp này, một bảng phương pháp ngoại lệ đặc biệt được chọn, nó chứa các bản ghi cho mỗi khối catch: loại ngoại lệ, hướng dẫn bắt đầu và hướng dẫn kết thúc. Nếu thứ tự của ngoại lệ là không chính xác, một số khối catch sẽ không thể truy cập được. Chắc chắn javac có thể sắp xếp các bản ghi trong bảng này cho nhà phát triển, nhưng nó không.

JVM Thông số kỹ thuật: 12

Thứ tự mà các trình xử lý ngoại lệ của một phương pháp đang tìm kiếm một trận đấu rất quan trọng. Trong một tệp lớp, các trình xử lý ngoại lệ cho mỗi phương thức được lưu trữ trong một bảng (§4.7.3). Vào thời gian chạy, khi một ngoại lệ được ném, Máy ảo Java sẽ tìm kiếm các trình xử lý ngoại lệ của phương thức hiện tại theo thứ tự chúng xuất hiện trong bảng xử lý ngoại lệ tương ứng trong tệp lớp, bắt đầu từ đầu bảng đó.

Miễn là ngoại lệ đầu tiên là phụ huynh thứ hai, khối thứ hai trở nên không tiếp cận được.

1

Java Language Specification §11.2.3 giải thích tình trạng này:

Đó là một lỗi thời gian biên dịch nếu mệnh đề catch có thể bắt kiểm tra lớp ngoại lệ E1 và bắt trước khoản của thử ngay kèm câu lệnh có thể bắt được E1 hoặc một siêu lớp của E1.

Version trong tiếng Anh đơn giản:

Nhiều trường hợp ngoại lệ chung phải sau những cái cụ thể. Các ngoại lệ chung khác phải sau các trường hợp ngoại lệ cụ thể.

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