Tại sao tôi nên viết tất cả các Tuyên bố trong Thử-Bắt?


12

Người đứng đầu công ty của tôi nói rằng tôi phải viết tất cả, tức là TẤT CẢ mã của tôi trong các câu lệnh Thử bắt. Bây giờ, tôi có thể hiểu cách tiếp cận 'tốt hơn là an toàn hơn xin lỗi' ở đây, nhưng không quá đau lòng khi nghĩ rằng sẽ có một ngoại lệ khi Nhãn được tạo, vị trí của biểu mẫu được đặt. đã có những trường hợp Ngoại lệ trong các hoạt động đơn giản như vậy.


4
Điều này nghe có vẻ như các thuật ngữ buzz của cùng một người nói rằng tất cả SQL nên được viết dưới dạng các thủ tục được lưu trữ để có hiệu suất tốt hơn.
spong

5
Bạn có thích, "Nếu mã của bạn tạo ra lỗi thời gian chạy, bạn sẽ bị sa thải." Trò chơi gà rất thú vị cho đến khi bạn thấy đối thủ quăng vô lăng và đạp phanh ra khỏi cửa sổ.
JeffO

4
@Jeff O - Tôi thực sự tin rằng trong phát triển phần mềm, đối thủ là một đoàn tàu chở hàng.
Joris Timmermans

5
Biểu hiện tốt nhất mà tôi đã nghe cho phong cách xử lý ngoại lệ này là "Đóng đinh xác chết ở vị trí thẳng đứng", nghĩa là, nó khiến ứng dụng rơi vào trạng thái bất ngờ. Thất bại nhanh, Thất bại là một cách tiếp cận hiện đại hơn nhiều, vì vậy bạn thực sự có thể giải quyết tất cả các lỗi.
Brook

2
Chủ đề của yêu cầu là không liên quan ... chỉ cần nói "người đứng đầu công ty của tôi nói rằng tôi nên viết mã ..." là một lá cờ đỏ lớn. Đó là quản lý vi mô ... đây không phải là công việc của anh ấy.
JoelFan

Câu trả lời:


14

Người đứng đầu công ty của tôi nói rằng tôi phải viết tất cả, tức là TẤT CẢ mã của tôi trong các câu lệnh Thử bắt.

Vâng, điều này là một chút quá mức và chỉ dẫn đến mã ồn ào. Những lợi ích của việc có tất cả các mã (mỗi phương thức, ví dụ) được viết bằng một trình xử lý bắt thử là gì? Nó chỉ cho bạn biết có một lỗi cần sửa trong hầu hết các trường hợp. Thông thường, ngoại lệ có thể và nên tránh ở nơi đầu tiên.

Một cái nhìn trên dấu vết ngăn xếp hầu hết là đủ để tiết lộ nguyên nhân trong mã của bạn, ngay cả khi phương thức lỗi không tự thực hiện việc bắt. Có những lúc các nhà phát triển tham nhũng dấu vết ngăn xếp trong các trường hợp ngoại lệ, nhưng đó là trường hợp thường xuyên hơn khi bạn có rất nhiều trình xử lý ngoại lệ. Giống như bất cứ điều gì: Một chút là tốt, nhưng quá nhiều trong số đó là chất độc.

Xử lý ngoại lệ thực sự khá đơn giản:

Bắt ngoại lệ

  • Bất cứ khi nào bạn cần một hành động đặc biệt như một phản ứng với ngoại lệ
  • Bất cứ khi nào một ngoại lệ sẽ rời khỏi chương trình trong trạng thái không nhất quán nếu không được xử lý

Nếu bạn nghĩ về nó, thì hầu như luôn luôn chỉ có một nơi tốt để xử lý một ngoại lệ xảy ra. Và do đó, người xử lý nên ở nơi đó.

Nhiều trường hợp ngoại lệ thậm chí không nên được ném ngay từ đầu, vì vậy đừng xây dựng các cấu trúc kiểm soát của bạn xung quanh việc xử lý ngoại lệ, thay vào đó hãy cố gắng tránh sự xuất hiện của ngoại lệ bất cứ khi nào và bất cứ khi nào có thể.

Hãy nhớ sụp đổ sớm khi mọi thứ đi (không sửa chữa) sai. Đặt tất cả các mã trong các câu lệnh thử là vô lý, nhưng đừng quên báo cáo và ghi lại TẤT CẢ các ngoại lệ.


+1 Không chỉ dẫn đến mã nhiễu, mà hiệu suất thậm chí còn tệ hơn. Khi bạn đặt các câu lệnh trong một khối thử, Trình biên dịch HotSpot sẽ không thể áp dụng các tối ưu hóa mà anh ta sẽ làm.
Oliver Weiler

@Oliver Weiler: Bạn có trích dẫn giải thích những gì tối ưu hóa trình biên dịch HotSpot không làm trong các khối thử / bắt không?
Kaypro II

16

nhưng không quá tâm huyết khi nghĩ rằng sẽ có một ngoại lệ khi các Nhãn được tạo, vị trí của biểu mẫu được đặt. đã có những trường hợp Ngoại lệ trong các hoạt động đơn giản như vậy.

Hoàn toàn đồng ý! Luôn có một cách để mọi thứ đi sai mà bạn không thấy trước. Và "lòng gà" là một cách diễn đạt vô lý để sử dụng trong bối cảnh này; phát triển phần mềm không phải là để chứng minh mach mach của bạn thông qua việc bỏ qua các vấn đề tiềm ẩn.

Có gì một câu hỏi hợp lệ là cho dù đó là hữu ích cho trường hợp ngoại lệ được bắt tại điểm mà tiêu chuẩn mã hóa của bạn nói rằng họ phải làm vậy. Câu lệnh của bạn đọc giống như bạn phải có khối thử / bắt xung quanh mọi thân phương thức và điều đó thực sự vô lý vì bạn thường không thể ngay lập tức làm điều gì đó hữu ích với một ngoại lệ, và đó thực sự là toàn bộ ngoại lệ: bạn có thể chọn để cho phép chúng tuyên truyền ngăn xếp cuộc gọi sẽ được xử lý tại điểm thích hợp.


13
Các ứng dụng của tôi biết rõ hơn là đưa ra các ngoại lệ hoặc chúng sẽ đánh bại cuộc sống của chúng. Một khi họ nghĩ bạn là người có trái tim gà, họ sẽ đánh sập bạn.
JeffO

@Michael Borgwardt: hehe, vì vậy bạn đã đánh giá thấp tôi. Bạn đã đánh giá thấp câu hỏi này và downvote duy nhất là trên bài viết của tôi. Bạn dường như có một vấn đề nghiêm trọng với cái tôi hoặc lòng tự trọng của bạn. Tôi nhận thấy rằng trên các câu hỏi khác, quá. Bạn biết đấy, các lập trình viên khác cũng có câu trả lời tốt.
Falcon

@Falcon: Tôi không đánh giá thấp bất cứ điều gì về câu hỏi này. Tôi không biết điều gì khiến bạn tin vào điều khác, nhưng nếu bất cứ ai có vấn đề về bản ngã nghiêm trọng, thì đó là bạn.
Michael Borgwardt

@Michael Borwardt: Có lẽ tôi sai. Trong trường hợp đó tôi xin lỗi. Nó có thể chỉ là downvote cho câu hỏi của riêng bạn khiến tôi nghĩ rằng bạn bị hạ thấp ở đây. Lấy làm tiếc.
Falcon

8

Tôi sẽ biến điều này theo cách khác. Vâng, như một xử lý ngoại lệ quy tắc chung là một điều tốt, nhưng bạn thực sự có thể xử lý mọi ngoại lệ có thể theo cách hợp lý tại điểm mà nó bị bắt không? Đôi khi, đặc biệt là nếu bạn không viết phần mềm nhiệm vụ quan trọng, nó tốt hơn để chỉ đơn giản là sụp đổ và đốt cháy trong một số cách nửa chiều kiểm soát khi mọi thứ đi sai lầm khủng khiếp.

Nếu bạn không thể chắc chắn 100% rằng bạn có thể xử lý mọi ngoại lệ duy nhất có thể bị bắt, thì có lẽ tốt hơn hết bạn nên viết một số trình xử lý ngoại lệ chung, bao bọc vòng lặp chính của chương trình - cơ chế chính xác về cách thực hiện điều đó rõ ràng phụ thuộc vào những gì ngôn ngữ mà bạn đang làm việc tại đây, đăng nhập càng nhiều chi tiết về ngoại lệ như bạn có thể, tiết kiệm nhà nước chương trình (ở đâu đó. khác hơn là bất kỳ dữ liệu lưu trữ cho người dùng hiện đang làm việc chống lại - hãy nhớ rằng, nó có thể tất cả các bị hỏng vào thời điểm này ), và như thế. Sau đó, suy nghĩ lại ngoại lệ và để HĐH xử lý nó theo cách phù hợp. Trong trình xử lý ngoại lệ bắt tất cả này, hãy chuẩn bị cho thất bại thảm khốc. Sau đó, khi chương trình được khởi động lại, hãy xem liệu trạng thái này có hữu ích không, và khôi phục lại những gì có thể được cứu vãn nếu có; và có thể đề nghị người dùng gửi báo cáo lỗi lại cho bạn.


5
+1: Không bao giờ bắt ngoại lệ nếu bạn không thể xử lý ngay lập tức. (Than ôi, đôi khi bạn phải bẫy nó chỉ để cho nó tự do đi lang thang nhưng được gắn thẻ là một loại khác, như là một phần của việc ép buộc API: Tôi ghét điều đó.)
Donal Fellows

6

Nhìn chung, việc sử dụng thử / bắt mà phần lớn không được dùng nữa, bởi vì khối bắt quá đắt từ điểm tài nguyên. Sử dụng thử / bắt nhắc nhở tôi về quản lý rủi ro . Quản lý rủi ro có hai khía cạnh:

  1. Xác suất rủi ro xảy ra
  2. Những thiệt hại nó có thể có

Bây giờ, nếu bạn đi ra khỏi nhà, một cây đàn piano rơi xuống đầu bạn ở đâu đó trong khi rất khó xảy ra (có thể là 0,001%), nhưng có thể giết chết bạn.

Xử lý ngoại lệ là như thế. Thử khối không đắt. Nhưng khối bắt thực sự tốn kém, bởi vì nó cần tạo một bảng theo dõi ngăn xếp và làm các công việc khác. Do đó, khi đưa ra quyết định về khối thử / bắt, bạn nên xem xét số lần bạn có thể nhấn khối bắt. Nếu trong số 10.000 lần sử dụng, bạn chỉ đánh nó 1 lần, sau đó sử dụng nó. Nhưng nếu đó là một hình thức và người dùng có thể không điền chính xác 50% lần, thì bạn nên tránh đưa khối thử / bắt vào hoạt động ở đó.

Ở những nơi có xác suất xảy ra ngoại lệ cao, nên sử dụng if {} else {}các khối để tránh xảy ra ngoại lệ. Ví dụ: nơi bạn muốn chia hai số, thay vì viết:

try
{
    int result = a/b;
}
catch (DivisionByZeroException ex)
{
    // Showing a message here, and logging of course.
}

bạn nên viết:

if (b == 0)
{
    int result = a/b;
}
else
{
    // Showing a message to user to change the value of b, etc.
}

2
+1 để sử dụng if / other để xử lý "ngoại lệ" về cơ bản chỉ là logic ứng dụng.
Morgan Herlocker

Nếu nó liên quan đến người dùng, hãy nhớ rằng máy tính nhanh hơn nhiều so với con người. Một ngoại lệ được ném trong 50% số lần gửi biểu mẫu vẫn chỉ có khả năng xảy ra vài lần một giây ngay cả với nhiều người dùng.
Donal Fellows

1
Tôi không đồng ý với bạn về việc tránh các khối thử / bắt. Liên tục cố gắng để dự đoán các ngoại lệ là dễ bị lỗi, tốn thời gian của nhà phát triển và làm cho mã của bạn khó đọc hơn. Một vòng lặp đưa ra một triệu trường hợp ngoại lệ và bắt chúng phải mất 500ms để chạy trên máy của tôi (so với 1ms cho một vòng lặp trống), đây không phải là sự khác biệt về hiệu suất trong thế giới thực trong 99,99% trường hợp (và tất cả mã UI). Bạn nên sử dụng các ngoại lệ ngoại trừ trong trường hợp bạn biết vấn đề phạt hiệu năng, bởi vì chúng làm cho mã của bạn đáng tin cậy hơn và cho phép bạn giả sử rằng mã trước đó được thực thi thành công.
Kaypro II

@ cosmic.osmo, bạn có lấy stacktrace hay chỉ bắt nó không?

3

Bạn nên sử dụng thử bắt khi thích hợp, nhưng xin vui lòng đừng bắt tất cả các ngoại lệ và thậm chí không đăng nhập nó. Tại thời điểm đó, mã mùi và công việc kém chất lượng.


1
+1 để đăng nhập. Các chương trình trong tự nhiên là hộp đen. Khi họ thất bại, một bản ghi có nội dung "Đây là những gì đã xảy ra" đi một chặng đường rất dài để giải quyết vấn đề. Tôi đã có lỗi trong các chương trình của mình mà không được báo cáo và chúng chỉ được phát hiện ra sau khi tôi tìm thấy chúng trong nhật ký.
Andrew Neely

2

Cá nhân tôi không thể chịu được ngoại lệ, họ RẤT, RẤT, RẤT khó xử lý chính xác. Và cố gắng để xóa dữ liệu tham nhũng là RẤT, RẤT, RẤT khó!

http://bloss.msdn.com/b/mgrier/archive/2004/02/18/75324.aspx

http://bloss.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx

http://bloss.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

http://www.joelonsoftware.com/items/2003/10/13.html

Nếu bạn không gọi mọi chức năng như:

try
{
    TrivialFunction();
}
catch(TypeAException)
{
    //MaybeFix
}
catch(TypeBException)
{
    //MaybeFix
}
catch(TypeCException)
{
    //NO FIX - CORRUPT DATA
}
catch(TypeDException)
{
    //NO FIX - UNKNOWN STATE
}
catch(OutOfMemoryException)
{
    //Try to fix this one! Destructors might allocate on their own ;)
}
catch(Exception)
{
    //Nothing to see here, move on, everything is OK ;)
}

Không có cách nào bạn sẽ dọn sạch chính xác trên mỗi điểm thoát. Ngoại lệ là CỨNG!

Điều tốt duy nhất về các trường hợp ngoại lệ là nếu bạn không bắt được chúng, ứng dụng sẽ gặp sự cố.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.