Sử dụng khẳng định so với ném ngoại lệ?


38

Thông thường khi tôi viết một hàm tôi muốn đảm bảo rằng các đầu vào của nó là hợp lệ để phát hiện các lỗi đó càng sớm càng tốt (tôi tin rằng đây được gọi là các điều kiện tiên quyết). Khi điều kiện tiên quyết thất bại, tôi luôn ném một ngoại lệ. Nhưng tôi bắt đầu nghi ngờ liệu đây có phải là cách thực hành tốt nhất và nếu không khẳng định sẽ phù hợp hơn.

Vậy khi nào tôi nên làm điều đó: khi nào thì thích hợp để sử dụng một xác nhận và khi nào thì thích hợp để đưa ra một ngoại lệ?


3
Tôi nghĩ rằng câu hỏi này nên được hỏi trên stackoverflow, mặc dù nó có thể đã được hỏi hàng chục lần ở đó, vì vậy bạn có thể đã tìm thấy nhiều câu trả lời ở đó.
user281377

Câu trả lời:


50

Các xác nhận chỉ nên được sử dụng để xác minh các điều kiện không thể sai về mặt logic (đọc: kiểm tra độ tỉnh táo). Những điều kiện này chỉ nên dựa trên các đầu vào được tạo bởi mã của riêng bạn. Bất kỳ kiểm tra dựa trên đầu vào bên ngoài nên sử dụng ngoại lệ.

Một quy tắc đơn giản mà tôi có xu hướng tuân theo là xác minh các đối số của hàm riêng bằng các xác nhận và sử dụng các ngoại lệ cho các đối số của hàm công khai / được bảo vệ.


Điểm tốt về việc sử dụng ngoại lệ cho đầu vào bên ngoài. Tôi cũng muốn thêm kết quả vào đó - các vấn đề khi cố gắng tạo / ghi vào tệp / cơ sở dữ liệu, v.v.
ChrisF

13
Và chắc chắn bạn sẽ thấy những khẳng định đó được kích hoạt trong sản xuất. +1 để xác minh nội dung riêng tư với các xác nhận! Có lẽ bạn có thể nói "sử dụng khẳng định khi bạn toàn quyền kiểm soát đầu vào"?
Frank Shearar

1
Trong java, ít nhất, bạn thường phải kích hoạt kiểm tra xác nhận với tham số dòng lệnh -ea. Điều này có nghĩa là các xác nhận là không có hiệu quả, trừ khi bạn bật chúng một cách rõ ràng.
Bill Michell

29

Các xác nhận được sử dụng để tìm lỗi lập trình. Các chương trình của bạn phải hoạt động tốt khi tất cả các xác nhận được xóa.

Mặt khác, ngoại lệ là dành cho các tình huống có thể xảy ra ngay cả khi chương trình hoàn hảo; chúng được gây ra bởi những tác động bên ngoài, như phần cứng, mạng, người dùng, v.v.


Đây là một cách khá tốt để đặt nó. Nếu người dùng nhập một cái gì đó không chính xác, ném một ngoại lệ. Nếu đầu vào là đúng nhưng vẫn có gì đó sai, hãy xác nhận.
Mateen Ulhaq

3

Thực hành lập trình điển hình là tổng hợp các xác nhận từ các bản dựng sản xuất / phát hành. Các xác nhận sẽ chỉ giúp trong quá trình thử nghiệm nội bộ để nắm bắt thất bại của các giả định. Bạn không nên thừa nhận hành vi của các cơ quan bên ngoài, vì vậy bạn không nên khẳng định về các sự kiện từ mạng hoặc người dùng. Ngoài ra, đó là một cách thực hành tốt để viết mã xử lý cho các bản dựng sản xuất trong trường hợp xác nhận thất bại.

Ví dụ trong C,

int printf(const char *fmt, ...)
{
  assert(fmt);  // may fail in debug build but not in production build
  if (!fmt) return -1; // handle gracefully in production build
  ...
}

Các ngoại lệ có nghĩa là được xây dựng thành các bản dựng sản xuất. Thay thế cho ngoại lệ là trả về lỗi và không xác nhận.


2
Tôi không nghĩ rằng đó là một ý tưởng tốt để đặt hành vi duyên dáng đằng sau một khẳng định cho cùng một điều kiện. Không thể tránh khỏi, vì hành vi duyên dáng chỉ tồn tại trong phiên bản sản xuất, mã được cho là xử lý hành vi duyên dáng sẽ bị kiểm tra kém và bị hỏng cũng như, nếu không tệ hơn, mã sẽ không được bảo vệ.
Sebastian Redl

0

Một vấn đề với các khẳng định đối với tôi là chúng bị tắt theo mặc định trong Java.

Chúng tôi sử dụng chiến lược thất bại đầu tiên trong đó chương trình - có thể đã chạy không được giám sát trong nhiều năm - cần phải sập càng sớm càng tốt để tránh hỏng dữ liệu trong trường hợp dữ liệu xấu (ở dạng không mong muốn). Đây là những gì chúng tôi sử dụng kiểm tra và bằng cách sử dụng các xác nhận, về cơ bản chúng tôi có nguy cơ chúng không hoạt động.

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.