2008-10-15 40 views
49

Ồ, tôi vừa lấy lại một dự án lớn trong C# từ các nhà phát triển bên ngoài và trong khi xem xét mã của tôi công cụ phân tích của tôi tiết lộ những thứ mà nó coi là xấu. Một trong những thông điệp làm nản lòng hơn nữa là:Có một lý do hợp lệ nào để bỏ qua một ngoại lệ bị bắt

Exceptions.DontSwallowErrorsCatchingNonspecificExceptionsRule : 2106 defects 

Các nhà phát triển đảm bảo với tôi rằng họ có lý do chính đáng cho tất cả các khối catch trống rỗng, mà đôi khi thử với catch khối rỗng chỉ có bỏ qua ngoại lệ vô dụng và giữ cho ứng dụng từ bị rơi. Tôi cảm thấy đây là một cảnh sát và hoàn thành BS. Một số ví dụ mà tôi thực sự tìm kiếm là các cuộc gọi cơ sở dữ liệu nơi bản ghi được lưu vào cơ sở dữ liệu, và trong trường hợp này, nếu một ngoại lệ bị bỏ qua, người dùng sẽ lấy lại lời nhắc không sao, nghĩ mọi thứ đều ổn, và tiếp tục với công việc của họ. Trong thực tế, công việc của họ chưa bao giờ được cứu. Tôi nghĩ đây là loại lỗi khủng khiếp nhất. Trong trường hợp này, họ hoàn toàn sai khi ném mã đó trong một lần thử với một khối catch rỗng. Nhưng câu hỏi của tôi là, "Liệu EVER này có được chấp nhận trong mọi tình huống không?" Tôi nghĩ không, nhưng tôi đã được biết là sai.

Trả lời

55

Mặc dù có một số lý do hợp lý để bỏ qua ngoại lệ; tuy nhiên, nói chung nó chỉ là những ngoại lệ cụ thể mà bạn có thể bỏ qua một cách an toàn. Như được ghi chú bởi Konrad Rudolph, bạn có thể phải nắm bắt và nuốt lỗi như là một phần của khuôn khổ; và như được ghi chú bởi osp70, có thể có một ngoại lệ được tạo bởi một khung mà bạn biết bạn có thể bỏ qua.

Trong cả hai trường hợp này, mặc dù có thể bạn sẽ biết loại ngoại lệ và nếu bạn biết loại sau đó bạn cần phải có mã tương tự như sau:

try { 
    // Do something that might generate an exception 
} catch (System.InvalidCastException ex) { 
    // This exception is safe to ignore due to... 
} catch (System.Exception ex) { 
    // Exception handling 
} 

Trong trường hợp của ứng dụng của bạn, là âm thanh giống như một cái gì đó tương tự có thể áp dụng trong một số trường hợp; nhưng ví dụ bạn cung cấp cho một cơ sở dữ liệu tiết kiệm trở lại một "OK" ngay cả khi có một ngoại lệ không phải là một dấu hiệu rất tốt.

+2

Chính xác ... nhiều như tôi ghét nó, khi nó là cần thiết, nó ít nhất nên xác định loại ngoại lệ được dự kiến ​​sẽ bị bỏ qua, để không bỏ qua một số lỗi mơ hồ. Và đăng nhập ở mức tối thiểu sẽ xảy ra. – stephenbayer

+2

Bạn đang tin tưởng thư viện của bên thứ ba không quá hăng hái trong việc ném ngoại lệ. Tôi không muốn spam tệp nhật ký của mình vì phán đoán xấu của người khác. Có những ngoại lệ đối với mọi quy tắc. –

+2

Và trong một trường hợp như Rob đã ở trên, tôi muốn giới thiệu một cái gì đó cụ thể hơn sau đó "an toàn để bỏ qua". Chú ý TẠI SAO ngoại lệ là an toàn để bỏ qua, nó sẽ không chỉ làm cho mã dễ hiểu hơn cho người khác, nó sẽ giúp bạn xuống đường khi bạn kiểm tra lại các dự án cũ. –

12

Đôi khi tôi sử dụng WebControl không bắt buộc phải hiển thị trang. Nếu nó không thành công, tôi không muốn ngăn trang hiển thị. Một ví dụ về WebControl không quan trọng sẽ là một ví dụ hiển thị quảng cáo.

Tuy nhiên, tôi đăng nhập lỗi. Tôi chỉ không nghĩ lại nó.

+0

Tôi sẽ không bận tâm nếu họ nghĩ lại nó nhiều ... những freak này chỉ là bỏ qua nó hoàn toàn. – stephenbayer

3

Tùy thuộc vào khung. Các khung công tác được triển khai kém có thể thực sự yêu cầu điều này. Tôi nhớ lại một hack trong VB6, nơi không có cách nào để xác định xem một bộ sưu tập có chứa một phần tử hay không. Cách duy nhất là cố gắng lấy lại nguyên tố và nuốt lỗi.

16

Tôi không bắt ngoại lệ trừ khi tôi định làm gì đó với họ. Bỏ qua chúng không làm điều gì đó về chúng.

+0

Không có gì sai với một phương pháp chọn bỏ qua một hoặc nhiều ngoại lệ mà nó có thể ném. Tuy nhiên, một phương thức như vậy nên ghi lại các ngoại lệ đó như là một phần của API của nó để người gọi có thể đưa ra quyết định về việc có nên xử lý chúng hay không. – DavidRR

6

trong mã quan trọng, có thể không, vì trạng thái của chương trình phải luôn được xác định chính xác. giống như ví dụ gọi cơ sở dữ liệu của bạn.

trong mã không tới hạn, chắc chắn, chúng tôi cũng làm như vậy (chúng tôi chỉ hiển thị các ngoại lệ bị bắt trong hộp thư và tiếp tục chạy). có thể một plugin hoặc mô-đun bị lỗi, nhưng chương trình chính không bị ảnh hưởng. có thể một lexical_cast không thành công và có một trục trặc văn bản được hiển thị trên màn hình. Không cần phải tạm dừng quá trình.

+1

Hiển thị một tin nhắn không phải là bằng cách bỏ qua ngoại lệ, vì vậy tôi không nghĩ rằng bạn đang đi khá xa như bỏ qua nó. – korona

4

Có, chấp nhận được (không thể tránh khỏi, cần thiết) trong một số trường hợp nhất định trên mỗi bài đăng của Maxim. Điều đó không có nghĩa là bạn phải thích nó. 2106 vi phạm có thể WAY quá nhiều và ít nhất họ nên có thêm một bình luận trong khối catch là tại sao nó là ok để nuốt ngoại lệ này.

@Dustin Thực tiễn kém để hiển thị mọi chi tiết ngoại lệ cho người dùng công cộng (dấu vết ngăn xếp, số dòng, v.v.). Bạn có lẽ nên đăng nhập ngoại lệ và hiển thị lỗi chung.

5

Một ví dụ về nơi tôi cho là có thể chấp nhận được trong một số mô-đun không quan trọng của ứng dụng quan trọng (ví dụ: trong mô-đun phản hồi âm thanh của hệ thống điều hướng không gian). được xử lý sạch hơn.

Trong những trường hợp đó, bạn không muốn để ngoại lệ đó lan truyền và làm cho toàn bộ ứng dụng bị lỗi (Xin lỗi, không có hệ thống điều hướng nào khác, mô-đun bíp của chúng tôi bị hỏng và chúng tôi không thể làm gì được).

Được chỉnh sửa để nói rằng trong bất kỳ trường hợp nào trong số này, bạn ít nhất cũng muốn đăng sự kiện ở đâu đó.

1

Đó là điều thực sự tồi tệ khi làm.

Trong khi có lý do hợp lệ bạn có thể bỏ qua ngoại lệ - nếu được mong đợi theo một cách nào đó và không cần phải làm gì - tuy nhiên thực hiện 2000 lần dường như họ chỉ muốn quét ngoại lệ của mình tấm thảm.

Ví dụ về nơi chấp nhận ngoại lệ có thể là tìm kiếm mọi thứ ... bạn gửi tin nhắn tới một số thiết bị hoặc mô-đun, nhưng bạn không quan tâm liệu nó có thực sự đến đó hay không.

5

Tôi nghĩ rằng nếu bạn có một khối catch trống, bạn cần ghi lại lý do tại sao nó trống để nhà phát triển tiếp theo sẽ biết. Ví dụ trên server.transfer một ngoại lệ web đôi khi bị ném. Tôi nắm bắt và nhận xét rằng chúng tôi có thể bỏ qua nó vì cuộc gọi chuyển.

8

Nói chung không, trên thực tế không có trong 99% của tất cả các trường hợp, NHƯNG

Có ngoại lệ. Một dự án tôi đã làm việc trên chúng tôi đã sử dụng thư viện của bên thứ ba để xử lý thiết bị TWAIN. Đó là lỗi và theo một số kết hợp phần cứng sẽ ném một lỗi con trỏ null. Tuy nhiên chúng tôi không bao giờ tìm thấy bất kỳ hoàn cảnh nào khi nó không thực sự quản lý để quét tài liệu trước khi nó đã làm điều đó - vì vậy việc bắt ngoại lệ hoàn toàn hợp lý. Vì vậy, tôi nghĩ rằng nếu đó là mã của bạn là ném ngoại lệ thì bạn nên luôn luôn kiểm tra nó, nhưng nếu bạn đang mắc kẹt với mã bên thứ ba thì trong một số trường hợp bạn có thể bị buộc phải ăn ngoại lệ và tiếp tục.

+0

Có, nhưng bạn nên để lại nhận xét cho biết lý do ngoại lệ cụ thể (ví dụ: "lỗi con trỏ null") có thể được bỏ qua một cách an toàn. – DavidRR

11

Cảm giác của tôi là bất kỳ khối catch trống nào cần nhận xét.

Có thể hợp lệ để bỏ qua một số lỗi nhất định, nhưng bạn cần ghi lại lý do của mình.

Ngoài ra, bạn sẽ không muốn biến nó trở thành "bắt (ngoại lệ e) {}" chung.

Bạn chỉ nên bắt loại lỗi cụ thể được mong đợi ở đó và được biết là được bỏ qua một cách an toàn.

4

Khi nói đến Ngoại lệ, luôn có ngoại lệ.

+1

Ah, nhưng có bao giờ an toàn để bỏ qua những ngoại lệ Ngoại lệ đó không? – stevemegson

0

Tôi nghĩ quy tắc tốt nhất của ngón tay cái chỉ là bỏ qua một ngoại lệ nếu bạn hoàn toàn nhận thức được ý nghĩa của ngoại lệ và các nhánh có thể có của nó. Trong trường hợp của một số module bị cô lập mà không ảnh hưởng đến phần còn lại của hệ thống của bạn, tôi nghĩ rằng nó sẽ là okay để chỉ bắt ngoại lệ chung miễn là bạn biết không có gì xấu xảy ra với bất cứ điều gì khác.

IMO dễ dàng hơn để biết các nhánh trong Java vì mỗi phương thức được yêu cầu khai báo tất cả các ngoại lệ mà nó có thể ném để bạn biết điều gì sẽ xảy ra, nhưng trong C# có thể ném ngoại lệ ngay cả khi nó không được ghi lại. khó biết tất cả các ngoại lệ có thể có thể được ném bởi một phương thức, và thiếu kiến ​​thức đó thường là một ý tưởng tồi để bắt tất cả.

8

Trường hợp khác mà bạn có thể được miễn để bắt và bỏ qua ngoại lệ là khi bạn đang kiểm tra đơn vị.

public void testSomething(){ 
    try{ 
     fooThatThrowsAnException(parameterThatCausesTheException); 
     fail("The method didn't throw the exception that we expected it to"); 
    } catch(SomeException e){ 
     // do nothing, as we would expect this to happen, if the code works OK. 
    } 
} 

Lưu ý rằng, mặc dù khối catch không có gì, nó giải thích lý do.

Nói xong, nhiều khuôn khổ kiểm tra gần đây (Junit4 & TestNG) cho phép bạn chỉ định các ngoại lệ mà được mong đợi - mà dẫn đến somthing như thế này ...

@Test(expected = SomeException.class) 
public void testSomething(){ 
    fooThatThrowsAnException(parameterThatCausesTheException); 
    fail("The method didn't throw the exception that we expected it to"); 
} 
1

Sau đây chỉ áp dụng cho ngôn ngữ mà đã kiểm tra ngoại lệ, ví dụ Java:

Đôi khi phương thức ném ngoại lệ đã chọn mà bạn biết sẽ không xảy ra, ví dụ: một số API java mong đợi một tên mã hóa như một chuỗi và ném một UnsupportedEncodingException nếu mã hóa đã cho không được hỗ trợ. Nhưng thường tôi vượt qua một chữ "UTF-8" mà tôi biết được hỗ trợ vì vậy tôi về mặt lý thuyết có thể viết một sản phẩm nào có.

Thay vì làm điều đó (bắt trống) Tôi thường ném một ngoại lệ không được kiểm soát chung bao gồm ngoại lệ "không thể", hoặc tôi thậm chí tuyên bố một lớp ImpossibleException mà tôi ném. Bởi vì lý thuyết của tôi về điều kiện lỗi đó là không thể có thể là sai và trong trường hợp đó tôi sẽ không muốn ngoại lệ bị nuốt chửng.

+0

Đối với trường hợp này, tôi sử dụng thành ngữ: ném lỗi mới ("Không phải xảy ra", e) –

7

Tôi đoán từ những gì tôi thu thập câu trả lời tốt nhất là nó có thể được phần nào chấp nhận được nhưng nên hạn chế. Bạn nên cố gắng sử dụng một giải pháp thay thế khác và nếu bạn không thể tìm thấy giải pháp thay thế khác, bạn nên biết đủ về cách mã hoạt động mà bạn có thể mong đợi các loại ngoại lệ cụ thể và không chỉ sử dụng chăn bắt tất cả "Ngoại lệ". Tài liệu về lý do tại sao ngoại lệ này được bỏ qua nên được bao gồm trong các hình thức của một bình luận dễ hiểu.

+0

Người đàn ông, tôi đã có rất nhiều công việc trước khi đi qua mã này mà tôi không mong đợi đến. Những nhà phát triển này làm tôi khó chịu. Nhưng ít nhất nó không phải là mã tồi tệ hơn tôi đã nhìn thấy. – stephenbayer

+0

Tôi nghĩ đó là một bản tóm tắt tuyệt vời. –

+0

chúc bạn may mắn. Tôi vẫn đang cố gắng sửa lỗi này sau một tuần. Nó chắc chắn là một việc vặt. – stephenbayer

1

Tôi muốn để hầu như tất cả các trường hợp ngoại lệ của mình phát sinh lên trình xử lý ứng dụng nơi chúng được ghi lại và thông báo lỗi chung được hiển thị cho người dùng cuối. Nhưng báo trước ở đây là không nên có nhiều ngoại lệ thực sự xảy ra. Nếu ứng dụng của bạn đang ném nhiều ngoại lệ, thì có thể có điều gì đó sai hoặc có thể đã được mã hóa tốt hơn. Đối với hầu hết các phần, tôi cố gắng để đảm bảo rằng mã của tôi kiểm tra các trường hợp đặc biệt trong nâng cao bởi vì tạo ra trường hợp ngoại lệ là tốn kém.

Là một mã nguồn ngoài gia công, nói chung là một ý tưởng tồi. Từ kinh nghiệm của tôi, thông thường họ là những nhà tư vấn, những người chỉ ở trong đó cho tiền lương và không có cổ phần trong sự thành công của dự án. Ngoài ra, bạn đầu hàng vào các tiêu chuẩn mã hóa của chúng (trừ khi bạn đã bao gồm trong hợp đồng).

2

Tôi nghĩ câu hỏi ban đầu đã được trả lời, nhưng một điều tôi muốn nói là nếu bạn cho rằng các nhà phát triển đã thuê ngoài/hợp đồng này tạo ra công việc kém chất lượng, bạn nên đảm bảo rằng những người phù hợp tại công ty của bạn biết nó.

Có thể có khả năng nó được gửi lại để làm lại, khoản thanh toán đó có thể được giữ lại một phần hoặc không được sử dụng lại cùng một công ty. Nếu công ty của bạn sử dụng các nhà thầu một lần nữa, họ có thể tìm cách để xây dựng các yêu cầu chất lượng trong các thỏa thuận, giả sử rằng đó không phải là quá đáng.

Nếu đây là công việc nội bộ, sẽ có hậu quả đối với nhóm/cá nhân sản xuất công việc không đạt tiêu chuẩn. Có lẽ điều đó chỉ có nghĩa là họ phải làm việc đêm và cuối tuần để sửa chữa nó, nhưng họ sẽ bị móc nối theo cách này hay cách khác. Điều tương tự cũng áp dụng cho các nhà thầu, thậm chí có thể nhiều hơn thế.

Chỉ cần cẩn thận giải thích vị trí của bạn một cách chuyên nghiệp và tập trung vào những gì tốt nhất cho công ty/sản phẩm. Bạn không muốn nó có vẻ như bạn đang phàn nàn, hoặc rằng bạn có một số loại phản đối chính trị để gia công phần mềm. Đừng nói về bạn. Làm cho nó về chi phí, thời gian để thị trường, sự hài lòng của khách hàng, vv Bạn biết đấy, tất cả những điều mà các loại quản lý quan tâm.

+0

Tôi đồng ý, nếu điều này sẽ gây ra một lượng đáng kể công việc cần phải thực hiện thì một số khoản thanh toán phải được giữ lại hoặc công ty phải được thông báo rằng họ cần sửa chữa mọi thứ. – rjzii

+0

Điều đó nghe có vẻ rất tốt về nguyên tắc. Nhưng liệu bạn có thực sự tin tưởng vào công ty ban đầu đã sản xuất mã xấu để khắc phục nó không? –

2

Tôi tự hỏi về điều này rất cụ thể.

Connection con = DriverManager.getConnection(url, "***", "***"); 

try { 
    PreparedStatement pStmt = con.prepareStatement("your query here"); 

    ... // query the database and get the results 
} 
catch(ClassNotFoundException cnfe) { 
    // real exception handling goes here 
} 
catch(SQLException sqle) { 
    // real exception handling goes here 
} 
finally { 
    try { 
     con.close(); 
    } 
    catch { 
     // What do you do here? 
    } 
} 

Tôi không bao giờ biết phải làm gì trong lần phát cuối cùng trong khối cuối cùng. Tôi chưa bao giờ thấy gần() ném một ngoại lệ trước đây, và nó không chắc rằng tôi không lo lắng về nó. Tôi chỉ cần đăng nhập ngoại lệ và tiếp tục.

+0

vâng, trong trường hợp đó, nó chỉ ở đó để giữ cho ứng dụng của bạn khỏi bị nổ tung trong trường hợp có một bản sao trong thời gian không gian liên tục và một cái gì đó thực sự kỳ lạ và bất ngờ xảy ra. – stephenbayer

+0

Có thể cho rằng, "ghi nhật ký ngoại lệ" không thực sự bỏ qua nó. Thực sự nuốt một ngoại lệ sẽ có nghĩa là một thất bại hoàn toàn im lặng. – DavidRR

5

Có những trường hợp chắc chắn có thể bắt được ngoại lệ cụ thể và không làm gì cả. Dưới đây là một ví dụ nhỏ:

public FileStream OpenFile(string path) 
    { 
     FileStream f = null; 
     try 
     { 
      f = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); 
     } 
     catch (FileNotFoundException) 
     { 
     } 
     return f; 
    } 

Bạn cũng có thể viết phương pháp theo cách này:

public FileStream OpenFile(string path) 
    { 
     FileStream f = null; 
     FileInfo fi = new FileInfo(path); 
     if (fi.Exists) 
     { 
      f = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);     
     } 
     return f; 
    } 

Trong trường hợp này, bắt các ngoại lệ là (rất) nhẹ an toàn hơn, như các tập tin có thể được xóa giữa thời gian bạn kiểm tra sự tồn tại của nó và thời gian bạn mở nó.

Có các lý do không phải để thực hiện việc này, chắc chắn. Trong .NET, các trường hợp ngoại lệ có tính toán tốn kém, vì vậy bạn muốn tránh bất kỳ thứ gì mà ném rất nhiều. (Trong Python, nơi mà các trường hợp ngoại lệ là rẻ, đó là một thành ngữ phổ biến để sử dụng các ngoại lệ để làm những việc như thoát khỏi vòng lặp.)

Nhưng đó là bỏ qua một ngoại lệ cụ thể cụ thể. Mã này:

catch 
{ 
} 

không thể sử dụng được.

Không có lý do chính đáng nào để không nắm bắt ngoại lệ được nhập cụ thể mà mã trong khối try sẽ bị ném. Lý do đầu tiên mà các nhà phát triển ngây thơ cung cấp cho việc bắt ngoại lệ không phân biệt loại, "Nhưng tôi không biết loại ngoại lệ nào có thể bị ném", là một câu trả lời cho câu hỏi.

Nếu bạn không biết loại ngoại lệ nào có thể bị ném, bạn không biết mã của mình có thể thất bại như thế nào. Nếu bạn không biết làm thế nào mã của bạn có thể thất bại, bạn không có cơ sở cho giả định rằng nó là OK để chỉ tiếp tục xử lý nếu nó.

1

Hãy suy nghĩ về cách này - nếu bạn đang mở rộng chu kỳ CPU để bắt ngoại lệ nhưng sau đó nuốt, bạn đang bỏ qua một vấn đề tiềm năng và lãng phí CPU. Như nhiều người đã nói rằng ứng dụng không nên ném nhiều ngoại lệ trừ khi bạn có thứ gì đó được xây dựng kém.

2

Trừ khi đang đánh bắt của bạn sẽ hoặc là

  1. Log trừ
  2. repackage trừ vào một ngoại lệ mà phù hợp với trừu tượng tương tự. và ném lại
  3. Xử lý các ngoại lệ theo cách bạn thấy phù hợp

Bạn có thể bỏ qua những ngoại lệ, nhưng ít nhất đề cập đến những ngoại lệ dự kiến ​​trong tài liệu phương pháp, vì vậy người tiêu dùng có thể mong đợi và xử lý nếu cần thiết

2

để lấy một ví dụ từ thế giới Java, nơi đó là OK để bỏ qua một ngoại lệ:

String foo="foobar"; 
byte[] foobytes; 

try 
{ 
    foobytes=foo.getBytes("UTF-8"); 
} 
catch (UnsupportedEncodingException uee) 
{ 
    // This is guaranteed by the Java Language Specification not to occur, 
    // since every Java implementation is required to support UTF-8. 
} 

Điều đó nói rằng, ngay cả trong những tình huống như thế này, tôi sẽ thường xuyên thay vì sử dụng

... 
catch (UnsupportedEncodingException uee) 
{ 
    // This is guaranteed by the Java Language Specification not to occur, 
    // since every Java implementation is required to support UTF-8. 
    uee.printStackTrace(); 
} 

Nếu máy ảo sẽ là điên/spec phá, có rất ít Tôi có thể làm gì về nó, nhưng với những vết đống, tôi ít nhất có được để ý khi nó bắt đầu gốc của nó trở nên điên loạn ..

1

Chúng tôi có một ứng dụng xử lý thay mặt cho các ứng dụng khác, nơi bạn chèn một số công việc (bộ sưu tập cấu hình) vào cơ sở dữ liệu và ứng dụng sẽ chạy và chạy nó vào thời điểm thích hợp. Chúng ta có xu hướng nuốt rất nhiều ngoại lệ trong ứng dụng đó, bởi vì ngay cả khi Job1 chết trong một thời trang khủng khiếp với một lỗi thảm khốc, chúng tôi muốn ứng dụng duy trì trạng thái sống để xử lý Job2.

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