Tôi đã lập trình được 3 năm qua. Khi tôi lập trình, tôi sử dụng để xử lý tất cả các ngoại lệ đã biết và cảnh báo người dùng một cách duyên dáng. Tôi đã thấy một số mã gần đây trong đó có gần như tất cả các phương pháp được bọc bên trong khối try/catch. Tác giả nói rằng nó là một phần của chương trình phòng thủ. Tôi tự hỏi, đây có phải là chương trình phòng thủ thực sự không? Bạn có đề nghị đặt tất cả mã của bạn trong các khối thử không?Không gói tất cả mọi thứ trong khối try/catch tạo thành lập trình phòng thủ?
Trả lời
Quy tắc cơ bản của tôi là: Trừ khi bạn có thể sửa lỗi vấn đề gây ra ngoại lệ, không bắt được nó, hãy để bong bóng đến mức có thể giải quyết được.
Theo kinh nghiệm của tôi, 95% tất cả các khối bắt hoặc chỉ bỏ qua ngoại lệ (catch {}
) hoặc chỉ ghi nhật ký lỗi và sửa lại ngoại lệ. Sau này có vẻ như là điều đúng đắn để làm, nhưng trong thực tế, khi điều này được thực hiện ở mọi cấp độ, bạn chỉ đơn thuần là kết thúc với nhật ký của bạn lộn xộn với năm bản sao của cùng một thông báo lỗi. Thông thường, các ứng dụng này có "bỏ qua bắt" ở cấp cao nhất (vì "chúng tôi đã thử/nắm bắt ở tất cả các cấp thấp hơn"), dẫn đến ứng dụng rất chậm với nhiều trường hợp ngoại lệ bị nhỡ và nhật ký lỗi quá dài bất cứ ai sẵn sàng nhìn qua nó.
Chính xác. Đặt mọi thứ vào một câu lệnh try/catch thường là dấu hiệu của một nhà phát triển thiếu kinh nghiệm, những người không biết nhiều về ngoại lệ IME. –
Chúng ta nên được phép mod + 2 nếu chúng ta dành điểm đại diện như downmodding. Nhưng tôi sẽ làm điều đó ở đây. –
Tôi nghĩ rằng đôi khi, đặc biệt khi vượt qua ranh giới của một mô-đun hoặc thư viện, thực hành tốt là nắm bắt ngoại lệ, bọc nó trong một loại ngoại lệ khác (như các cơ sở nguyên nhân của Java) và quay lại. – rmeador
Có một điều như quá trình xử lý "quá nhiều" và bắt tất cả các ngoại lệ sẽ đánh bại điểm. Cụ thể cho C++, câu lệnh catch (...) bắt tất cả ngoại lệ nhưng bạn không thể xử lý nội dung của ngoại lệ đó vì bạn không biết loại ngoại lệ (và nó có thể là bất kỳ thứ gì).
Bạn nên nắm bắt các ngoại lệ mà bạn có thể xử lý toàn bộ hoặc một phần, tính lại các ngoại lệ một phần. Bạn không nên bắt bất kỳ ngoại lệ nào mà bạn không thể xử lý, bởi vì điều đó sẽ chỉ làm xáo trộn các lỗi có thể (hoặc đúng hơn, sẽ) cắn bạn sau này.
Tôi đoán câu trả lời thực sự là "Phụ thuộc". Nếu các khối try-catch đang bắt các ngoại lệ rất chung chung thì tôi sẽ nói đó là lập trình phòng thủ theo cùng một cách mà không bao giờ lái xe ra khỏi khu phố của bạn là lái xe phòng thủ. Một try-catch (imo) nên được điều chỉnh theo các ngoại lệ cụ thể.
Một lần nữa, đây chỉ là ý kiến của tôi, nhưng khái niệm lập trình phòng thủ của tôi là bạn cần ít hơn/nhỏ hơn khối try-catch không nhiều hơn/lớn hơn. Mã của bạn nên làm mọi thứ có thể để đảm bảo rằng một điều kiện ngoại lệ không bao giờ có thể tồn tại ngay từ đầu.
Tôi khuyên bạn nên chống lại thực tiễn này. Đưa mã vào các khối try-catch khi bạn biết các loại ngoại lệ có thể bị ném là một chuyện. Nó cho phép bạn, như bạn đã nói, để khôi phục một cách duyên dáng và/hoặc cảnh báo người dùng về lỗi. Tuy nhiên, đặt tất cả các mã của bạn bên trong các khối như vậy, nơi bạn không biết lỗi nào có thể xảy ra là sử dụng các ngoại lệ để kiểm soát luồng chương trình, điều này là không lớn.
Nếu bạn đang viết mã có cấu trúc tốt, bạn sẽ biết về mọi ngoại lệ có thể xảy ra và có thể nắm bắt được những ngoại lệ đó. Nếu bạn không biết làm thế nào một ngoại lệ cụ thể có thể được ném, sau đó không bắt nó, chỉ trong trường hợp. Khi nó xảy ra, sau đó bạn có thể tìm ra ngoại lệ, những gì gây ra nó, và sau đó bắt nó.
Ghi ngoại lệ ngẫu nhiên là xấu. Vậy thì sao?
- Bỏ qua chúng? Xuất sắc. Hãy cho tôi biết làm thế nào mà làm việc cho họ.
- Đăng nhập và tiếp tục chạy? Tôi nghĩ là không.
- Ném một ngoại lệ khác như một phần của sự cố? Chúc may mắn gỡ lỗi đó.
Ghi ngoại lệ mà bạn thực sự có thể làm điều gì đó có ý nghĩa là tốt. Những trường hợp này dễ xác định và duy trì.
Khó gỡ lỗi gì về # 3? –
@Bart van Heukelom: Ngoại lệ khác mà mặt nạ ngoại lệ ban đầu làm cho các bản ghi khó hiểu. Thông điệp tường trình là "SomeRandomException". Nguyên nhân gốc là ValueError. Hơn nữa, các traceback ban đầu có thể dễ dàng bị lạc trong muddle của nâng cao một ngoại lệ mới. Thử nó. –
Đó là những gì gây ra chuỗi Java gây ra. Tôi giả định các ngôn ngữ khác có điều này quá (tôi biết ngay cả PHP 5.3 không). –
Thuật ngữ "lập trình phòng thủ" là viết tắt của mã viết theo cách sao cho nó có thể khôi phục từ các tình huống lỗi hoặc tránh tình trạng lỗi hoàn toàn. Ví dụ:
private String name;
public void setName(String name) {
}
Bạn xử lý tên == null như thế nào? Bạn có ném một ngoại lệ hay bạn chấp nhận nó? Nếu nó không có ý nghĩa để có một đối tượng không có tên, thì bạn nên ném một ngoại lệ. Còn tên == "" thì sao?
Nhưng ... sau đó bạn viết trình chỉnh sửa. Trong khi bạn thiết lập giao diện người dùng, bạn thấy rằng có những tình huống mà người dùng có thể quyết định lấy tên hoặc tên có thể bị trống trong khi người dùng chỉnh sửa nó.
Một ví dụ khác:
public boolean isXXX (String s) {
}
Ở đây, chiến lược phòng thủ thường là để trả về false null khi s == (tránh NPEs khi bạn có thể).
Hoặc:
public String getName() {
}
Một lập trình phòng thủ có thể trở về "" nếu tên == null để tránh NPEs kêu gọi mã.
Tôi có thể nói một điều ở đây là mỗi khi một trong những đồng nghiệp của tôi viết chữ ký phương thức với "ném ngoại lệ" thay vì liệt kê các loại ngoại lệ mà phương pháp thực sự ném, tôi muốn đi qua và bắn chúng trong đầu? Vấn đề là sau một thời gian bạn đã có 14 cấp độ của tất cả các cuộc gọi nói rằng "ném ngoại lệ", do đó, tái cấu trúc để làm cho họ tuyên bố những gì họ thực sự ném là một bài tập lớn.
Đồng ý hết lòng! Ẩn dụ, tất nhiên. Không thực sự ủng hộ việc bắn bất cứ ai trong bất kỳ phần nào của người của họ. –
Chỉ cần viết một phương thức gọi là shootProgrammer (Programmer p) ném OutOfAmmoException – Elie
@Bill - là nó ok nếu tôi smack chúng với một tờ báo cuộn lên sau đó? –
Nếu bạn đang đi để xử lý ngoại lệ ngẫu nhiên, xử lý chúng trong chỉ một nơi - trên đỉnh của các ứng dụng, nhằm mục đích:
- trình bày một thông điệp thân thiện với người dùng, và
- lưu chẩn đoán.
Đối với mọi thứ khác, bạn muốn có sự cố ngay lập tức, vị trí cụ thể nhất, để bạn nắm bắt những điều này càng sớm càng tốt - ngoại trừ việc xử lý ngoại lệ trở thành cách ẩn thiết kế và mã độc.
Trong hầu hết các trường hợp ngoại lệ có thể dự đoán được, có thể kiểm tra trước thời hạn, với điều kiện mà trình xử lý ngoại lệ sẽ bắt.
Nói chung, Nếu ... Khác thì tốt hơn nhiều so với Thử ... Bắt.
Tôi không đồng ý. Có những ngoại lệ mà bạn xử lý theo cách đó, nhưng có những ngoại lệ bạn xử lý sâu - ví dụ, một số mã của tôi ném một "ScheduleConflictException", và một vài cấp cao hơn có mã để thay đổi lịch biểu và thử lại. –
@Paul, "Trong hầu hết các trường hợp", và tôi nghĩ ngoại lệ cá nhân là ngoại lệ. Trong trường hợp này, bạn đang tạo một ngoại lệ để xử lý cao hơn, và tôi không thấy điều này như những gì cris5gd đang xem xét như một trường hợp chung. –
@Paul Và điều này nghe có vẻ như không phải là một ngoại lệ ... –
Không, đó không phải là "lập trình phòng thủ". Đồng nghiệp của bạn đang cố gắng hợp lý hoá thói quen xấu của mình bằng cách sử dụng một từ thông dụng cho một thói quen tốt.
Điều anh ấy đang làm nên được gọi là "quét nó dưới tấm thảm". Nó giống như thống nhất (void)
-giá trị trả về trạng thái lỗi từ các cuộc gọi phương thức.
Tôi có cho thấy tuổi của tôi bằng cách nói rằng tôi ngay lập tức nhắc nhở in printf "không phải là một máy đánh chữ" không có vấn đề gì errno được? –
Sử dụng rộng rãi Thử ... Bắt không phải là lập trình phòng thủ, chỉ cần đóng đinh xác chết ở vị trí thẳng đứng.
Thử ... Cuối cùng có thể được sử dụng rộng rãi để phục hồi khi đối mặt với các ngoại lệ không mong muốn. Chỉ khi bạn mong đợi một ngoại lệ và bây giờ làm thế nào để đối phó với nó, bạn nên sử dụng Try..Catch thay thế.
Thỉnh thoảng tôi thấy Try..Catch System.Exception, trong đó khối catch chỉ ghi lại ngoại lệ và quay lại. Có ít nhất 3 vấn đề với cách tiếp cận đó:
- Trả lại giả định một ngoại lệ chưa được giải quyết và do đó chương trình sẽ chấm dứt vì nó ở trạng thái không xác định. Nhưng bắt gây ra các khối cuối cùng bên dưới khối catch để chạy. Trong một tình huống không xác định, mã trong các khối Cuối cùng này có thể làm cho vấn đề tồi tệ hơn.
- Mã trong những khối Cuối cùng này sẽ thay đổi trạng thái chương trình. Vì vậy, bất kỳ đăng nhập nào sẽ không nắm bắt trạng thái chương trình thực tế khi ngoại lệ ban đầu được ném. Và việc điều tra sẽ khó khăn hơn bởi vì nhà nước đã thay đổi.
- Nó mang lại cho bạn trải nghiệm gỡ lỗi khốn khổ, bởi vì trình gỡ lỗi dừng lại trên sự phục hồi, không phải là lần ném gốc.
+1 cho 'đánh bóng xác chết' – ChrisA
Tôi đã tìm thấy "cố gắng" "bắt" các khối rất hữu ích, đặc biệt nếu bất kỳ thời gian thực nào (chẳng hạn như truy cập cơ sở dữ liệu) được sử dụng.
Quá nhiều? Mắt của kẻ si tình.
Tôi thấy rằng sao chép nhật ký vào Word và tìm kiếm bằng "tìm" - nếu trình đọc nhật ký không có "tìm" hoặc "tìm kiếm" như một phần của công cụ được bao gồm - đơn giản nhưng tuyệt vời cách đăng nhập thông qua nhật ký chi tiết.
Chắc chắn có vẻ như "phòng thủ" theo nghĩa thông thường của từ đó.
Tôi đã tìm thấy, thông qua trải nghiệm, để theo dõi bất kỳ điều gì người quản lý, trưởng nhóm hoặc đồng nghiệp của bạn làm. Nếu bạn chỉ đang lập trình cho chính mình, hãy sử dụng chúng cho đến khi mã "ổn định" hoặc trong các bản dựng lỗi và sau đó xóa chúng khi hoàn tất.
Trong C++, một lý do để viết nhiều khối try/catch là lấy dấu vết ngăn xếp của trường hợp ngoại lệ được ném. Những gì bạn làm là viết một try/catch ở khắp mọi nơi, và (giả sử bạn không ở đúng chỗ để đối phó với ngoại lệ) có log catch một số thông tin dấu vết sau đó lại ném ngoại lệ. Bằng cách này, nếu một ngoại lệ bong bóng tất cả các con đường lên và gây ra chương trình chấm dứt, bạn sẽ có một dấu vết ngăn xếp đầy đủ của nơi mà tất cả bắt đầu đi sai (nếu bạn không làm điều này, sau đó một ngoại lệ C++ unhandled sẽ đã giúp bạn tháo gỡ ngăn xếp và loại bỏ bất kỳ khả năng nào của bạn để tìm ra nó xuất phát từ đâu).
Tôi sẽ tưởng tượng rằng trong bất kỳ ngôn ngữ nào có xử lý ngoại lệ tốt hơn (nghĩa là ngoại lệ không cho bạn biết chúng đến từ đâu), bạn chỉ muốn bắt ngoại lệ nếu bạn có thể làm gì đó cho chúng. Nếu không, bạn chỉ làm cho chương trình của bạn khó đọc.
- 1. Lập trình phòng thủ
- 2. Hỗ trợ xác nhận jQuery/lập trình phòng thủ?
- 3. Git kéo không kéo tất cả mọi thứ
- 4. Lập trình phòng thủ và xử lý ngoại lệ
- 5. Làm thế nào để thử tất cả mọi thứ?
- 6. thông số hàng loạt: tất cả mọi thứ sau% 1
- 7. Mọi trình duyệt có hỗ trợ tất cả unicode không?
- 8. python tạo mọi thứ từ heap?
- 9. Làm thế nào để thiết lập lại tất cả mọi thứ Heroku trong Git của tôi/Rails 3.1 Dự án
- 10. bash awk cột 1 đầu tiên và cột thứ 3 với tất cả mọi thứ sau
- 11. Yêu cầu kiểm tra: cách thiết lập chung cho tất cả các phòng thử nghiệm
- 12. Ruby, chạy lệnh linux từng cái một, bằng SSH và LOG tất cả mọi thứ
- 13. Regex - phù hợp với tất cả mọi thứ mà không cần khoảng trắng
- 14. Java xử lý sử dụng máy chủ proxy, hosing lên tất cả mọi thứ
- 15. Regex loại bỏ tất cả mọi thứ sau: (bao gồm cả :)
- 16. zend không sử dụng cột, và chọn tất cả mọi thứ
- 17. MySQL SELECT tất cả mọi thứ vào một chuỗi lớn (cột và hàng)
- 18. Cách đơn giản để lập trình có được tất cả các thủ tục được lưu trữ
- 19. Java: lập trình xác định tất cả tên gói được tải trên đường dẫn lớp
- 20. Mở đầu cách thêm tất cả mọi thứ từ tệp ngôn ngữ trong vòng lặp php
- 21. Chọn tất cả mọi thứ sau một hàng nhất định trong Bảng SQL đặt hàng
- 22. Nhận tất cả mọi thứ sau và trước nhân vật nào đó trong SQL Server
- 23. thực hành mã hóa phòng thủ
- 24. Cách lấy danh sách tất cả các thủ tục bên trong một gói oracle
- 25. CSS Tôi muốn một div nằm ở trên cùng của tất cả mọi thứ
- 26. Loại bỏ thẻ hình ảnh html và tất cả mọi thứ ở giữa từ một chuỗi
- 27. MKOverlay phủ tất cả mọi thứ với các trường hợp lạ chỉ trên ios5?
- 28. Tại sao/như thế nào là tất cả mọi thứ $() dựa trên jQuery?
- 29. DDD - Kho lưu trữ cho mỗi thực thể hoặc một cho tất cả mọi thứ?
- 30. Xem trên đầu trang của tất cả mọi thứ: UIWindow subview VS UIViewController subview
Không chắc chắn về điều đó. Các câu hỏi, trong khi có tiêu đề chung, thực sự là khá cụ thể về việc sử dụng trường hợp ngoại lệ như một phương pháp lập trình phòng thủ, và những gì là những mối quan tâm với làm như vậy. – Elie