Hiệu quả sử dụng thử / bắt khối?


21

Có nên sử dụng các khối bắt để viết logic tức là xử lý điều khiển luồng vv? Hay chỉ để ném ngoại lệ? Liệu nó có ảnh hưởng đến hiệu quả hoặc khả năng duy trì của mã?

Các tác dụng phụ (nếu có) của logic viết trong khối bắt là gì?

CHỈNH SỬA:

Tôi đã thấy một lớp Java SDK trong đó họ đã viết logic bên trong khối bắt. Ví dụ: đoạn trích được lấy từ java.lang.Integerlớp):

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? new Integer(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            String constant = negative ? new String("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }

EDIT2 :

Tôi đã trải qua một hướng dẫn trong đó họ coi đó là một lợi thế của việc viết logic các trường hợp ngoại lệ bên trong các ngoại lệ:

Các ngoại lệ cho phép bạn viết luồng chính của mã của mình và xử lý các trường hợp ngoại lệ ở nơi khác.

Bất kỳ hướng dẫn cụ thể khi viết logic trong khối bắt và khi nào không?


12
@Coder Tôi nghĩ bạn tăng trưởng quá mức một chút. Đặc biệt là với nhiều API hiện có, bạn không thể tránh nó.
CodeInChaos

8
@Coder: Trong các ngoại lệ Java thường được sử dụng như một cơ chế để báo hiệu các vấn đề là một phần của dòng mã hợp pháp. Chẳng hạn, nếu bạn cố mở một tệp và nó không thành công, thư viện Java sẽ cho bạn biết rằng bằng cách ném một ngoại lệ, vì các API dẫn đến mở tệp không có cơ chế trả lại lỗi nào khác.
JeremyP

4
@Coder Phụ thuộc. Tôi nghĩ rằng khi thực hiện IO hoặc khi phân tích dữ liệu phức tạp, hầu như luôn được định dạng chính xác, việc đưa ra một ngoại lệ để biểu thị một lỗi làm cho mã sạch hơn nhiều.
CodeInChaos

1
@ Mã hóa Có, phương thức thực thi là có phương thức để cho bạn biết nó không thể làm những gì được yêu cầu. Nhưng các trường hợp ngoại lệ không nên được sử dụng để kiểm soát luồng, đó là lý do tại sao C # cũng có phương thức int.TryPude không ném.
Andy

1
@Coder: Đó là thứ rác rưởi. Những điều đặc biệt ở một cấp mã có thể không phải là ngoại lệ ở cấp độ khác - hoặc bạn có thể muốn, ví dụ, trình bày hoặc thêm thông tin lỗi hoặc gỡ lỗi trước khi tiếp tục.
DeadMG

Câu trả lời:


46

Ví dụ bạn trích dẫn là do thiết kế API kém (không có cách rõ ràng nào để kiểm tra xem Chuỗi có phải là số nguyên hợp lệ hay không, ngoại trừ cố gắng phân tích cú pháp và bắt ngoại lệ).

Ở cấp độ kỹ thuật, ném và thử / bắt là các cấu trúc luồng điều khiển cho phép bạn nhảy lên ngăn xếp cuộc gọi, không hơn không kém. Nhảy lên ngăn xếp cuộc gọi ngầm kết nối mã không gần nhau trong nguồn, điều này không tốt cho khả năng bảo trì . Vì vậy, nó chỉ nên được sử dụng khi bạn cần làm điều đó và các lựa chọn thay thế thậm chí còn tồi tệ hơn. Các trường hợp được chấp nhận rộng rãi nơi lựa chọn thay thế là tồi tệ hơn là xử lý lỗi (mã trở lại đặc biệt mà cần phải được kiểm tra và thông qua lên mỗi cấp độ của các cuộc gọi stack thủ công).

Nếu bạn gặp trường hợp các lựa chọn thay thế tệ hơn (và bạn thực sự đã xem xét tất cả chúng một cách cẩn thận), thì tôi sẽ nói sử dụng ném và thử / bắt cho luồng điều khiển là tốt. Giáo điều không phải là một thay thế tốt cho sự phán xét.


1
+1, điểm tốt được thực hiện. Tôi nghĩ rằng một số xử lý có thể hợp lệ trong việc nắm bắt như chuẩn bị thông báo lỗi và ghi nhật ký lỗi. Giải phóng các tài nguyên đắt tiền như kết nối db và tham chiếu COM (.NET) có thể được thêm vào khối Cuối cùng.
NoChance

@EmmadKareem Tôi đã nghĩ về việc giải phóng tài nguyên, nhưng thường thì bạn phải giải phóng chúng bằng mọi cách ngay cả khi không có tình huống lỗi. Do đó bạn có thể lặp lại chính mình. Chuẩn bị một thông điệp tường trình là tất nhiên chấp nhận được.
Scarfridge

@MichaelBorgwardt Tôi nghĩ rằng thiết kế API không quá kém (mặc dù nó có thể tốt hơn). Cố gắng phân tích một chuỗi không hợp lệ rõ ràng là một điều kiện lỗi và do đó chính xác là "trường hợp được chấp nhận rộng rãi" mà bạn đã đề cập. Đồng ý, một phương pháp để xác định xem một chuỗi có đúng về mặt cú pháp hay không có ích (đây là nơi có thể tốt hơn). Tuy nhiên, buộc mọi người phải gọi phương thức này trước khi phân tích cú pháp thực tế là không thể và chúng tôi cần xử lý lỗi. Trộn kết quả thực tế và mã lỗi là không thoải mái và vì vậy bạn vẫn sẽ ném ngoại lệ. Nhưng có lẽ một ngoại lệ thời gian chạy.
Scarfridge

3
+1 cho câu cuối cùng đó.
Thất vọngWithFormsDesigner

2
@scarfridge: Tôi hoàn toàn đồng ý với bạn :) Sự vắng mặt của phương thức isInteger (String) boolean return return là tất cả những gì tôi muốn nói với "thiết kế API kém"
Michael Borgwardt

9

Đây là một cái gì đó có xu hướng phụ thuộc vào ngôn ngữ và mô hình.

Hầu hết công việc của tôi được thực hiện bằng Java (và đôi khi là C ++). Xu hướng là chỉ sử dụng ngoại lệ cho các điều kiện đặc biệt. Có một số câu hỏi về Stack Overflow về chi phí hoạt động của các ngoại lệ trong Java và như bạn có thể thấy, nó không chính xác không đáng kể. Ngoài ra còn có các mối quan tâm khác, chẳng hạn như khả năng đọc và duy trì của mã. Khi được sử dụng đúng cách, các ngoại lệ có thể ủy quyền xử lý lỗi cho các thành phần thích hợp.

Tuy nhiên, trong Python, ý tưởng rằng việc xin tha thứ sẽ dễ dàng hơn so với sự cho phép ngự trị. Trong cộng đồng Python, cái này được gọi là EAFP , tương phản với cách tiếp cận "nhìn trước khi bạn nhảy" ( LBYL ) trong các ngôn ngữ kiểu C.


2
+1 để đề cập đến chi phí ngoại lệ. Tôi làm .NET và (ít nhất là trên máy của tôi) Tôi thậm chí có thể cảm thấy khi một ngoại lệ sắp xảy ra theo thời lượng trong một số trường hợp so với các hoạt động bình thường khác.
NoChance

2
@EmmadKareem Chỉ khi bạn có trình gỡ lỗi được đính kèm. Bạn có thể ném vài nghìn trong số chúng mỗi giây mà không cần trình gỡ lỗi.
CodeInChaos

@CodeInChaos, bạn đã đúng. Làm sao tôi biết được, tôi viết một mã sạch như vậy mà không bao giờ có được bất kỳ lúc nào chạy :)
NoChance

@EmmadKareem Tùy thuộc vào cách người ta viết một ứng dụng mạng, lỗi kết nối hoặc giao thức được xử lý với một ngoại lệ. Các ngoại lệ cần phải nhanh chóng hợp lý trong một ứng dụng như vậy để tránh các cuộc tấn công DoS tầm thường.
CodeInChaos

@CodeInChaos, điều này là tốt để biết. Tôi đã đùa trong bình luận cuối cùng của tôi.
NoChance

9

Đó không phải là cách tốt nhất để suy nghĩ về các khối thử / bắt. Cách nghĩ về các khối thử / bắt là thế này: một thất bại đã xảy ra, đâu là nơi tốt nhất để đối phó với thất bại cụ thể NÀY. Đó có thể là dòng mã tiếp theo, nó có thể là hai mươi cấp trong chuỗi cuộc gọi. Bất cứ nơi nào nó là, đó là nơi nó nên được.

Khối bắt làm gì phụ thuộc vào lỗi và bạn có thể làm gì với nó. Đôi khi, đơn giản là có thể bỏ qua (không xóa được tệp cào không có dữ liệu bất hợp pháp trong đó), đôi khi nó sẽ được sử dụng để đặt giá trị trả về của hàm thành đúng hoặc sai (phương thức phân tích cú pháp của java), đôi khi bạn sẽ thoát khỏi chương trình . Tất cả điều đó phụ thuộc vào lỗi.

Phần quan trọng cần hiểu là: bắt khối == Tôi biết cách xử lý vấn đề này.


6

Các khối bắt chỉ nên được sử dụng để xử lý các ngoại lệ, không có gì khác và không bao giờ cho luồng điều khiển. Trong mọi tình huống mà bạn muốn sử dụng ngoại lệ để quản lý luồng, bạn nên kiểm tra các điều kiện trước.

Xử lý dòng chảy với các ngoại lệ là chậm và không chính xác về mặt ngữ nghĩa.


4
Tôi biết những gì bạn đang nói, nhưng điều đáng chú ý là tất cả các ngoại lệ đó là xử lý luồng chương trình - chỉ là nó chỉ nên được sử dụng để kiểm soát luồng lỗi đặc biệt ...
Tối đa

Không có hướng dẫn cụ thể nào khi viết logic trong khối bắt và khi nào không?
HashimR

4
Trình phân tích cú pháp số và trình định dạng văn bản của Java là những ví dụ nổi tiếng về việc sử dụng ngoại lệ có vấn đề: cách hợp lý duy nhất để kiểm tra điều kiện tiên quyết (chuỗi đó đại diện cho số có thể phân tích cú pháp) là thử phân tích cú pháp và nếu thất bại với ngoại lệ, lựa chọn của bạn là gì trong thực tế? Bạn phải nắm bắt ngoại lệ và quản lý dòng chảy với nó, bất kể điều đó được coi là không chính xác về mặt ngữ nghĩa.
Joonas Pulakka

@JoonasPulakka Tôi nghĩ rằng bình luận của bạn wrt Số trình phân tích cú pháp và Trình định dạng văn bản đủ điều kiện là một câu trả lời kích thước đầy đủ cho câu hỏi này
gnat

5

Có nên sử dụng các khối bắt để viết logic tức là xử lý điều khiển luồng vv? Hay chỉ để ném ngoại lệ? Liệu nó có ảnh hưởng đến hiệu quả hoặc khả năng duy trì của mã?

Đầu tiên, hãy quên khái niệm rằng "ngoại lệ nên được sử dụng cho các điều kiện đặc biệt". Cũng đừng lo lắng về hiệu quả, cho đến khi bạn có mã thực hiện không được chấp nhận và bạn đã đo lường để biết vấn đề nằm ở đâu.

Mã dễ hiểu nhất khi các hành động tuân theo một trình tự đơn giản, không có điều kiện. Các ngoại lệ cải thiện khả năng bảo trì bằng cách loại bỏ kiểm tra lỗi từ luồng bình thường. Sẽ không thành vấn đề nếu việc thực hiện tuân theo luồng thông thường 99,9% thời gian hoặc 50% thời gian hoặc 20% thời gian.

Ném một ngoại lệ khi một hàm không thể trả về một giá trị, khi một thủ tục không thể hoàn thành hành động mong đợi hoặc khi một hàm tạo không thể tạo ra một đối tượng có thể sử dụng được. Điều này cho phép các lập trình viên giả định rằng một hàm luôn trả về một kết quả có thể sử dụng được, một thủ tục luôn hoàn thành hành động được yêu cầu, một đối tượng được xây dựng luôn ở trạng thái có thể sử dụng được.

Vấn đề lớn nhất tôi thấy với mã xử lý ngoại lệ là các lập trình viên viết các khối thử / bắt khi không nên. Ví dụ, trong hầu hết các ứng dụng web, nếu một yêu cầu cơ sở dữ liệu đưa ra một ngoại lệ, thì không có gì có thể được thực hiện trong bộ điều khiển. Một điều khoản bắt chung chung ở mức cao nhất là đủ. Sau đó, mã điều khiển có thể vui vẻ bỏ qua khả năng đĩa bị hỏng hoặc cơ sở dữ liệu ngoại tuyến hoặc bất cứ điều gì.


1

Các khối bắt không nên được sử dụng để viết logic mã. Chúng chỉ nên được sử dụng để xử lý lỗi. Một ví dụ là (1) dọn sạch mọi tài nguyên được phân bổ, (2) in một thông điệp hữu ích và (3) thoát một cách duyên dáng.

Đúng là ngoại lệ có thể bị lạm dụng và gây ra gototác dụng không mong muốn . Nhưng điều đó không làm cho chúng vô dụng. Khi được sử dụng đúng cách , chúng có thể cải thiện nhiều khía cạnh của mã của bạn.

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.