Đối số cho hoặc không sử dụng Thử / Bắt làm toán tử logic [đã đóng]


36

Tôi vừa phát hiện ra một số mã đáng yêu trong ứng dụng công ty của chúng tôi sử dụng các khối Try-Catch làm toán tử logic.
Có nghĩa là, "làm một số mã, nếu điều đó ném lỗi này, hãy thực hiện mã này, nhưng nếu điều đó ném lỗi này, hãy làm điều thứ 3 thay thế".
Nó sử dụng "Cuối cùng" là câu lệnh "khác" mà nó xuất hiện.
Tôi biết rằng điều này là sai vốn có, nhưng trước khi tôi đi chọn một cuộc chiến, tôi đã hy vọng cho một số tranh luận được suy nghĩ tốt.
Và này, nếu bạn có tranh luận về việc sử dụng Thử bắt theo cách này, xin vui lòng cho biết.

Đối với bất kỳ ai đang tự hỏi, ngôn ngữ là C # và mã được đề cập là khoảng hơn 30 dòng và đang tìm kiếm các ngoại lệ cụ thể, nó không xử lý TẤT CẢ các ngoại lệ.


13
Tôi chỉ có lập luận chống lại thực tiễn này, và vì bạn dường như đã bị thuyết phục rằng đó là một ý tưởng tồi, tôi sẽ không bận tâm đăng chúng.
Thất vọngWithFormsDesigner

15
@FrustratedWIthFormsDesigner: Đó là lý do tồi. Còn những người không bị thuyết phục thì sao? Điều gì về câu hỏi thực tế của tôi khi tôi đặc biệt hỏi lý do vì tôi thực sự không thể nói "tại sao" chỉ là tôi biết nó sai.
James P. Wright

3
Ý kiến ​​của tôi phụ thuộc rất nhiều vào những gì mã trong câu hỏi thực sự làm. Có những thứ không thể được kiểm tra trước (hoặc cho phép điều kiện cuộc đua khi cố gắng, chẳng hạn như nhiều thao tác tệp - trong độ trễ giữa kiểm tra và thao tác, bất kỳ điều gì cũng có thể xảy ra với tệp) và phải là try'd. Không phải mọi trường hợp ngoại lệ bảo đảm một ngoại lệ nói chung đều phải gây tử vong trong trường hợp cụ thể này. Vì vậy, bạn có thể làm điều đó một cách đơn giản, bình đẳng hoặc mạnh mẽ hơn mà không cần sử dụng ngoại lệ?

11
Tôi hy vọng họ không thực sự sử dụng khối "cuối cùng" làm "khác" vì khối "cuối cùng" luôn được chạy sau mã trước bất kể trường hợp ngoại lệ nào được đưa ra.
jimreed

2
Họ đang sử dụng ngôn ngữ nào? Nó là hoàn toàn tốt trong, nói, OCaml, nơi thư viện tiêu chuẩn ném ngoại lệ thường xuyên. Xử lý ngoại lệ là rất rẻ đó. Nhưng nó sẽ không hiệu quả trong CLI hoặc JVM.
SK-logic

Câu trả lời:


50

Xử lý ngoại lệ có xu hướng là một cách tốn kém để xử lý kiểm soát luồng (chắc chắn cho C # và Java).

Thời gian chạy thực hiện khá nhiều công việc khi một đối tượng ngoại lệ được xây dựng - kết hợp dấu vết ngăn xếp với nhau, tìm ra nơi xử lý ngoại lệ và hơn thế nữa.

Tất cả chi phí này trong bộ nhớ và tài nguyên CPU không cần phải mở rộng nếu các câu lệnh điều khiển luồng được sử dụng cho điều khiển luồng.

Ngoài ra, có một vấn đề ngữ nghĩa. Các ngoại lệ dành cho các tình huống đặc biệt, không phải cho kiểm soát dòng chảy thông thường. Người ta nên sử dụng xử lý ngoại lệ để xử lý các tình huống không dự đoán / ngoại lệ, không phải như luồng chương trình thông thường, bởi vì nếu không, một ngoại lệ chưa được xử lý sẽ cho bạn biết ít hơn nhiều.

Ngoài hai điều này, còn có vấn đề của những người khác đọc mã. Sử dụng các ngoại lệ theo cách như vậy không phải là điều mà hầu hết các lập trình viên sẽ mong đợi, vì vậy khả năng đọc và mã của bạn dễ hiểu như thế nào. Khi nhìn thấy "Ngoại lệ", người ta nghĩ - điều gì đó tồi tệ đã xảy ra, điều gì đó không được phép xảy ra bình thường. Vì vậy, sử dụng các ngoại lệ theo cách này chỉ là khó hiểu.


1
Một điểm tốt về hiệu suất, mặc dù điều này cũng sẽ phụ thuộc vào chi tiết cụ thể của nền tảng.
Thất vọngWithFormsDesigner

4
Nếu đó là nhược điểm duy nhất, xin cảm ơn - Tôi sẽ từ bỏ hiệu suất bất kỳ ngày nào nếu nó mua cho tôi mã tốt hơn (ngoại trừ trong các đường dẫn quan trọng về hiệu năng, nhưng may mắn thay, đó chỉ là 20% của tất cả các mã ngay cả trong các ứng dụng nói chung là hiệu suất -chỉ trích).

5
@delnan - Không, không phải nhược điểm duy nhất.
Oded

2
Khác với từ unaticipated tôi đồng ý với bài viết của bạn. Có những lúc trong mã của bạn, nơi ngoại lệ xảy ra. Hầu hết trong số chúng nên được dự đoán như lỗi kết nối với DB hoặc cuộc gọi dịch vụ hoặc bất cứ khi nào bạn đang xử lý mã không được quản lý. Bạn nắm bắt các vấn đề ngoài tầm kiểm soát của bạn và giải quyết chúng. Nhưng tôi đồng ý bạn không bao giờ nên kiểm soát luồng dựa trên các ngoại lệ mà bạn có thể tránh trong mã của mình.
SoylentGray

4
"Xử lý ngoại lệ có xu hướng là một cách tốn kém để xử lý kiểm soát dòng chảy". Sai cho Python.
S.Lott

17

Tôi vừa phát hiện ra một số mã đáng yêu trong ứng dụng của công ty chúng tôi sử dụng các khối Try-Catch làm toán tử logic. Có nghĩa là, "làm một số mã, nếu điều đó ném lỗi này, hãy thực hiện mã này, nhưng nếu điều đó ném lỗi này, hãy làm điều thứ 3 thay thế". Nó sử dụng "Cuối cùng" là câu lệnh "khác" mà nó xuất hiện. Tôi biết rằng điều này vốn đã sai ...

Làm sao bạn biết điều đó? Tôi đã từ bỏ tất cả các loại "kiến thức" đó và bây giờ chỉ tin rằng mã đơn giản nhất là tốt nhất. Giả sử bạn muốn chuyển đổi một chuỗi thành Tùy chọn trống nếu phân tích cú pháp thất bại. Không có gì sai với:

try { 
    return Optional.of(Long.valueOf(s)); 
} catch (NumberFormatException) { 
    return Optional.empty(); 
}

Tôi hoàn toàn không đồng ý với cách giải thích thông thường của "Ngoại lệ là cho các điều kiện đặc biệt". Khi một hàm không thể trả về giá trị có thể sử dụng hoặc một phương thức không thể đáp ứng các điều kiện hậu của nó, hãy ném một ngoại lệ. Không quan trọng tần suất các ngoại lệ này được ném cho đến khi có vấn đề về hiệu suất được chứng minh.

Các ngoại lệ đơn giản hóa mã, bằng cách cho phép tách xử lý lỗi khỏi luồng bình thường. Chỉ cần viết mã đơn giản nhất có thể, và nếu sử dụng try-Catch hoặc ném ngoại lệ dễ dàng hơn, thì hãy làm điều đó.

Các ngoại lệ đơn giản hóa việc kiểm tra bằng cách giảm số lượng đường dẫn thông qua mã. Một hàm không có nhánh sẽ hoàn thành hoặc ném ngoại lệ. Một hàm có nhiều ifcâu lệnh để kiểm tra mã lỗi có nhiều đường dẫn có thể. Rất dễ để có một trong những điều kiện sai hoặc quên hoàn toàn một điều kiện, do đó một số điều kiện lỗi bị bỏ qua.


4
Tôi nghĩ rằng đây thực sự là một lập luận khá tốt. Mã của bạn sạch sẽ và súc tích và có ý nghĩa trong những gì nó đang làm. Điều này thực sự giống với những gì đang xảy ra trong mã tôi đang thấy, chỉ có điều nó phức tạp hơn nhiều, được lồng vào nhau và kéo dài hơn 30 dòng mã.
James P. Wright

@James: có vẻ như mã sẽ ổn nếu bạn trích xuất một số phương thức nhỏ hơn.
kevin cline

1
Người ta có thể lập luận rằng Java thực sự có thể sử dụng một cái gì đó giống như TryPude của C #. Trong C # mã đó sẽ là int i; if(long.TryParse(s, out i)) return i; else return null;. TryPude trả về false nếu chuỗi không thể được phân tích cú pháp. Nếu nó có thể được phân tích cú pháp, nó đặt đối số đầu ra thành kết quả của phân tích cú pháp và trả về true. Không có trường hợp ngoại lệ nào xảy ra, (ngay cả trong nội bộ trong TryPude) và đặc biệt không có trường hợp ngoại lệ nào thuộc loại có nghĩa là lỗi lập trình viên, như .NET FormatExceptionluôn chỉ ra.
Kevin Cathcart

1
@Kevin Cathcart, nhưng tại sao điều đó tốt hơn? mã bắt NumberFormatException đối với tôi rõ ràng hơn nhiều sau đó kiểm tra kết quả của TryPude để tìm null.
Winston Ewert

1
@ChrisMiskowiec, tôi nghi ngờ cái nào bạn thấy rõ hơn là vấn đề của những gì bạn đã quen. Tôi thấy việc bắt ngoại lệ dễ dàng hơn nhiều để theo dõi sau đó kiểm tra các giá trị ma thuật. Nhưng đó là tất cả chủ quan. Về mặt khách quan, tôi nghĩ chúng ta nên ưu tiên các ngoại lệ vì chúng có mặc định lành mạnh (sập chương trình), thay vào đó là một mặc định che giấu lỗi (tiếp tục như thể không có gì xảy ra). Đúng là .NET hoạt động kém với các ngoại lệ. Nhưng đó là kết quả của thiết kế của .NET, không phải là bản chất của ngoại lệ. Nếu trên .NET, vâng, bạn phải làm điều đó. Nhưng về nguyên tắc, ngoại lệ là tốt hơn.
Winston Ewert

12

Công việc gỡ lỗi và bảo trì rất khó khăn khi luồng điều khiển được thực hiện bằng các ngoại lệ.

Về cơ bản, các trường hợp ngoại lệ được thiết kế để trở thành một cơ chế thay đổi luồng điều khiển thông thường của chương trình của bạn - thực hiện các hoạt động bất thường, gây ra tác dụng phụ bất thường, như một cách để thoát khỏi một ràng buộc đặc biệt chặt chẽ mà không thể xử lý ít phức tạp hơn có nghĩa. Ngoại lệ là đặc biệt. Điều này có nghĩa là, tùy thuộc vào môi trường cụ thể mà bạn đang làm việc, việc sử dụng ngoại lệ cho luồng kiểm soát thường xuyên có thể gây ra:

  • Không hiệu quả Các vòng lặp bổ sung mà môi trường phải nhảy qua để thực hiện một cách an toàn các thay đổi bối cảnh tương đối khó khăn cần thiết cho các ngoại lệ đòi hỏi phải có dụng cụ và tài nguyên.

  • Khó khăn gỡ lỗi Đôi khi thông tin hữu ích (khi cố gắng gỡ lỗi chương trình) thông tin bị ném ra ngoài cửa sổ khi có ngoại lệ xảy ra. Bạn có thể mất dấu vết của trạng thái chương trình hoặc lịch sử có liên quan để hiểu hành vi thời gian chạy

  • Vấn đề bảo trì Lưu lượng thực thi khó theo dõi qua các bước nhảy ngoại lệ. Ngoài ra, một ngoại lệ có thể bị ném từ bên trong mã loại hộp đen, có thể không hoạt động theo những cách dễ hiểu khi ném ngoại lệ.

  • Các quyết định thiết kế kém Các chương trình được xây dựng theo cách này khuyến khích một khung suy nghĩ, trong hầu hết các trường hợp, không dễ dàng ánh xạ để giải quyết vấn đề một cách thanh lịch. Sự phức tạp của chương trình cuối cùng không khuyến khích lập trình viên hiểu được việc thực hiện đầy đủ và khuyến khích đưa ra các quyết định dẫn đến cải tiến ngắn hạn với chi phí dài hạn cao.


10

Tôi đã thấy mô hình này được sử dụng nhiều lần.

Có 2 vấn đề lớn:

  • Nó cực kỳ tốn kém (khởi tạo đối tượng ngoại lệ, thu thập ngăn xếp cuộc gọi, v.v.). Một số trình biên dịch thực sự có thể có thể tối ưu hóa nó đi, nhưng tôi sẽ không tính đến điều đó trong trường hợp này, vì các trường hợp ngoại lệ không dành cho việc sử dụng đó, do đó bạn không thể mong đợi mọi người tối ưu hóa cho nó.
  • Sử dụng ngoại lệ cho luồng điều khiển trong thực tế là một bước nhảy, giống như a goto. Nhảy được coi là có hại, vì một số lý do. Chúng nên được sử dụng, nếu tất cả các lựa chọn thay thế có nhược điểm đáng kể. Trong thực tế, trong tất cả các mã của tôi, tôi chỉ nhớ lại 2 trường hợp, trong đó nhảy rõ ràng là giải pháp tốt nhất.

2
Chỉ cần đặt nó ra khỏi đó, nếu / khác cũng được coi là một bước nhảy. Sự khác biệt là đó là một bước nhảy chỉ có thể xảy ra tại điểm cụ thể đó (và nó dễ đọc hơn nhiều) và bạn không phải lo lắng về tên của các nhãn (mà bạn không phải thử / bắt , nhưng so với goto). Nhưng chỉ cần nói "đó là một bước nhảy, đó là xấu" cũng nói rằng nếu / khác là xấu, khi nó không.
jsternberg

1
@jsternbarg: Có, nếu / khác trên thực tế được biên dịch để nhảy ở cấp độ máy, nhưng ở cấp độ ngôn ngữ, mục tiêu nhảy là câu lệnh tiếp theo, trong trường hợp vòng lặp, đó là câu lệnh hiện tại. Tôi sẽ lập luận rằng đó là một bước, hơn là một bước nhảy;)
back2dos

9

Đôi khi ngoại lệ là nhanh nhất. Tôi đã thấy các trường hợp ngoại lệ đối tượng null nhanh hơn ngay cả trong Java so với việc sử dụng các cấu trúc điều khiển (tôi không thể trích dẫn nghiên cứu tại thời điểm này, vì vậy bạn sẽ phải tin tưởng tôi). Vấn đề xuất hiện khi Java phải thực sự dành thời gian và điền vào dấu vết ngăn xếp của một lớp ngoại lệ tùy chỉnh thay vì sử dụng các lớp gốc (dường như được lưu trữ ít nhất một phần). Trước khi nói rằng một cái gì đó đơn phương nhanh hơn hoặc chậm hơn, nó sẽ là tốt để điểm chuẩn.

Trong Python, nó không chỉ nhanh hơn mà còn đúng hơn khi làm điều gì đó có thể gây ra ngoại lệ và sau đó xử lý lỗi. Vâng, bạn có thể thực thi một hệ thống loại, nhưng điều đó đi ngược lại triết lý của ngôn ngữ - thay vào đó bạn chỉ cần cố gắng gọi phương thức và bắt kết quả! (Kiểm tra xem một tệp có thể ghi được tương tự hay không - chỉ cần thử ghi vào tệp và bắt lỗi).

Tôi đã thấy nhiều lần nhanh hơn khi làm điều gì đó ngu ngốc như các bảng truy vấn không có ở đó hơn là tìm hiểu xem một bảng có tồn tại trong PHP + MySQL hay không ( câu hỏi mà tôi đánh giá đây thực sự là câu trả lời được chấp nhận duy nhất của tôi với phiếu bầu tiêu cực) .

Tất cả những gì đã nói, việc sử dụng các ngoại lệ nên được giới hạn vì một số lý do:

  1. Tình cờ nuốt phải ngoại lệ lồng nhau. Đây là chính. Nếu bạn bắt gặp một số ngoại lệ lồng nhau sâu sắc mà người khác đang cố gắng xử lý, bạn vừa bắn người lập trình viên đồng nghiệp của mình (thậm chí là bạn!) Vào chân.
  2. Các xét nghiệm trở nên không rõ ràng. Một khối mã có ngoại lệ trong đó có thể có một trong những điều sai với nó. Mặt khác, một boolean, về mặt lý thuyết có thể gây khó chịu khi gỡ lỗi, nhưng nhìn chung thì không. Điều này đặc biệt đúng khi các try...catchtín đồ dòng điều khiển nói chung (theo kinh nghiệm của tôi) không tuân theo triết lý "tối thiểu hóa mã trong khối thử".
  3. Nó không cho phép một else ifkhối. Đủ nói (và nếu ai đó phản đối "Nhưng họ có thể sử dụng các lớp ngoại lệ khác nhau", câu trả lời của tôi là "Đi đến phòng của bạn và không đi ra ngoài cho đến khi bạn nghĩ về những gì bạn đã nói.")
  4. Đó là sai ngữ pháp. Exception, với phần còn lại của thế giới (như không tuân thủ try...catchtriết lý dòng chảy kiểm soát), có nghĩa là một cái gì đó đã đi vào trạng thái không ổn định (mặc dù có thể phục hồi). Các trạng thái không ổn định là BAD và nó sẽ giữ tất cả chúng ta vào ban đêm nếu chúng ta thực sự có những ngoại lệ có thể tránh được (nó thực sự làm tôi khó chịu, không nói dối).
  5. Nó không phù hợp với phong cách mã hóa phổ biến. Công việc của chúng tôi, cả với mã của chúng tôi và với UI của chúng tôi là làm cho thế giới rõ ràng nhất có thể. try...catchkiểm soát dòng chảy đi ngược lại với những gì thường được coi là thực tiễn tốt nhất. Điều này có nghĩa là phải mất nhiều thời gian hơn cho người mới tham gia dự án để tìm hiểu dự án, điều đó có nghĩa là sự gia tăng số giờ làm việc hoàn toàn không có lợi.
  6. Điều này thường dẫn đến sao chép mã. Cuối cùng, các khối, mặc dù điều này không thực sự cần thiết, cần phải giải quyết tất cả các con trỏ lơ lửng bị bỏ ngỏ bởi khối thử bị gián đoạn. Vì vậy, hãy thử khối. Điều này có nghĩa là bạn có thể có một try{ obj.openSomething(); /*something which causes exception*/ obj.doStuff(); obj.closeSomething();}catch(Exception e){obj.closeSomething();}. Trong một if...elsekịch bản truyền thống hơn, closeSomething()ít có khả năng (một lần nữa, kinh nghiệm cá nhân) là một công việc sao chép và dán. (Phải thừa nhận rằng, lập luận cụ thể này có liên quan nhiều đến những người tôi đã gặp hơn là chính triết lý thực tế).

AFAIK, # 6 là một vấn đề chỉ có trong Java, không giống như mọi ngôn ngữ hiện đại khác, không có sự đóng cửa cũng như quản lý tài nguyên dựa trên ngăn xếp. Đó chắc chắn không phải là một vấn đề cố hữu trong việc sử dụng các ngoại lệ.
kevin cline

4 và 5 dường như là cùng một điểm với tôi. 3-6 không áp dụng nếu ngôn ngữ của bạn là python. 1 và 2 là các vấn đề tiềm ẩn, nhưng tôi nghĩ rằng chúng được xử lý bằng cách giảm thiểu mã trong khối thử.
Winston Ewert

1
@Winston tôi không đồng ý. 1 và 2 là những vấn đề lớn, trong khi giảm dần bởi các tiêu chuẩn mã hóa tốt hơn, vẫn khiến người ta tự hỏi liệu có thể không tốt hơn để tránh lỗi tiềm ẩn bắt đầu hay không. 3 áp dụng nếu ngôn ngữ của bạn là Python. 4-5 cũng có thể áp dụng cho Python nhưng họ không phải làm vậy. 4 và 5 là những điểm rất khác nhau - gây hiểu lầm khác với sự khác biệt về phong cách. Mã gây hiểu lầm có thể đang làm một cái gì đó như đặt tên kích hoạt để khởi động xe, "nút dừng". Về mặt phong cách, mặt khác, nó cũng có thể tương tự như tránh tất cả các vết lõm khối trong C.
cwallenpoole

3) Python có một khối khác cho các trường hợp ngoại lệ. Nó rất hữu ích để tránh các vấn đề bạn thường gặp trong 1 và 2.
Winston Ewert

1
Nói rõ hơn, tôi không ủng hộ việc sử dụng ngoại lệ là cơ chế kiểm soát dòng chảy chung của bạn. Tôi ủng hộ việc ném một ngoại lệ cho bất kỳ loại chế độ "thất bại" nào, dù nhỏ đến đâu. Tôi nghĩ rằng phiên bản xử lý ngoại lệ sạch hơn và ít có khả năng che giấu lỗi hơn phiên bản kiểm tra giá trị trả về. Và lý tưởng, tôi muốn các ngôn ngữ để làm cho việc bắt lỗi lồng nhau trở nên khó khăn hơn.
Winston Ewert

4

Đối số chính của tôi là việc sử dụng try / Catch cho logic sẽ phá vỡ luồng logic. Theo "logic" thông qua các cấu trúc phi logic là (đối với tôi) phản trực giác và khó hiểu. Tôi đã quen đọc logic của mình là "nếu Điều kiện thì A khác B". Đọc cùng một câu như "Thử A bắt rồi thực hiện B" cảm thấy kỳ lạ. Sẽ còn kỳ quặc hơn nữa nếu câu lệnh Alà một phép gán đơn giản, yêu cầu mã bổ sung để buộc một ngoại lệ nếu conditionlà sai (và làm như vậy có thể sẽ yêu cầu một phân tầng ifnào đó).


2

Chà, chỉ là vấn đề về nghi thức, trước khi "bắt đầu tranh luận với họ", như bạn nói, tôi sẽ vui lòng hỏi "Tại sao họ sử dụng xử lý ngoại lệ ở tất cả những nơi khác nhau này?"

Ý tôi là, có một số khả năng:

  1. họ bất tài
  2. có một lý do hoàn toàn hợp lệ cho những gì họ đã làm, có thể không xuất hiện từ cái nhìn đầu tiên.
  3. đôi khi nó là một câu hỏi về hương vị và có thể đơn giản hóa một số dòng chương trình phức tạp.
  4. Đó là một di tích của quá khứ chưa ai thay đổi và họ sẽ rất vui nếu ai đó làm điều đó

... Tôi nghĩ tất cả những thứ này đều có khả năng như nhau. Vì vậy, chỉ cần hỏi họ độc đáo.


1

Hãy thử Catch chỉ nên được sử dụng để xử lý ngoại lệ. Hơn nữa, xử lý ngoại lệ đặc biệt. Thử bắt của bạn chỉ nên bắt ngoại lệ dự kiến, khôn ngoan khác nó không được hình thành tốt. Nếu bạn cần sử dụng một lần bắt tất cả hãy thử bắt, thì có lẽ bạn đang làm sai điều gì đó.

CHỈNH SỬA:

Lý do: Bạn có thể lập luận rằng nếu bạn sử dụng thử bắt như một toán tử có điều kiện, Làm thế nào bạn sẽ tính đến các ngoại lệ THỰC SỰ?


2
OP đang hỏi lý do / lập luận. Bạn đã không cung cấp bất kỳ.
Oded

"Bạn có thể lập luận rằng nếu bạn sử dụng thử bắt như một toán tử có điều kiện, làm thế nào bạn sẽ tính đến các ngoại lệ THỰC SỰ?" - Bằng cách bắt những ngoại lệ thực sự đó trong một catchmệnh đề khác với mệnh đề bắt ngoại lệ "không thực"?

@del Nam - Cảm ơn bạn! bạn đã chứng minh một điểm tôi sắp thực hiện. Nếu một người trả lời những gì bạn vừa nói với cả lý do của tôi và Oded, tôi sẽ ngừng nói vì anh ta không tìm kiếm lý do anh ta chỉ bướng bỉnh và tôi không lãng phí thời gian của mình với sự bướng bỉnh.
AJC

Bạn đang gọi tôi bướng bỉnh vì tôi chỉ ra sai sót trong một số lập luận được liệt kê ở đây? Lưu ý làm thế nào tôi không có gì để nói với các điểm khác được nêu ở đây. Tôi không phải là người thích sử dụng các ngoại lệ để kiểm soát dòng chảy (mặc dù tôi sẽ không lên án bất cứ điều gì nếu không có chi tiết, do đó, truy vấn của tôi để xây dựng bởi OP), tôi chỉ đơn thuần là người ủng hộ quỷ dữ.

1
Sử dụng try-Catch như một toán tử có điều kiện không có cách nào ngăn nó hoạt động để cũng bắt được các ngoại lệ "thực".
Winston Ewert

1

Ngoại lệ là khi điều đặc biệt xảy ra. Là chương trình hoạt động theo quy trình công việc thường xuyên đặc biệt?


1
Nhưng tại sao? Điểm của câu hỏi là tại sao (hoặc tại sao không) ngoại lệ chỉ tốt cho điều đó.
Winston Ewert

Không phải lúc nào cũng "đặc biệt". Không tìm thấy khóa trong hashtable không phải là ngoại lệ, ví dụ, và thư viện OCaml có xu hướng đưa ra một ngoại lệ trong những trường hợp như vậy. Và nó là ok - xử lý ngoại lệ là rất rẻ ở đó.
SK-logic

1
-1: tuyên bố tautological
Cookies Rice Rice

1

Lý do sử dụng ngoại lệ:

  1. Nếu bạn quên bắt gặp một tình huống đặc biệt, chương trình của bạn sẽ chết và dấu vết ngăn xếp sẽ cho bạn biết chính xác lý do tại sao. Nếu bạn quên xử lý giá trị trả về cho một trường hợp ngoại lệ, sẽ không cho biết chương trình của bạn sẽ thể hiện hành vi không chính xác bao xa.
  2. Sử dụng giá trị trả về chỉ hoạt động nếu có giá trị sentinel bạn có thể trả về. Nếu tất cả các giá trị trả về có thể đã hợp lệ, bạn sẽ làm gì?
  3. Một ngoại lệ sẽ mang thêm thông tin về những gì đã xảy ra có thể hữu ích.

Lý do không sử dụng ngoại lệ:

  1. Nhiều ngôn ngữ không được thiết kế để làm cho ngoại lệ nhanh chóng.
  2. Các ngoại lệ di chuyển nhiều lớp lên ngăn xếp có thể để lại trạng thái không nhất quán trong trạng thái của chúng

Đến cuối cùng:

Mục tiêu là viết mã truyền đạt những gì đang diễn ra. Các ngoại lệ có thể giúp / cản trở tùy thuộc vào những gì mã đang làm. Thử / bắt trong python cho KeyError trên tham chiếu từ điển là hoàn toàn (miễn là bạn biết ngôn ngữ) thử / bắt cho cùng một lớp chức năng KeyError năm lớp là nguy hiểm.


0

Tôi sử dụng try-> Catch như điều khiển luồng trong các tình huống nhất định. Nếu logic chính của bạn phụ thuộc vào điều gì đó không thành công, nhưng bạn không muốn ném ngoại lệ và thoát ... Đó là những gì một khối thử-> bắt dành cho. Tôi viết rất nhiều tập lệnh unix phía máy chủ không được giám sát, và điều quan trọng hơn nhiều đối với họ là không thất bại, hơn là để họ thất bại một cách đáng yêu.

Vì vậy, hãy thử Kế hoạch A và nếu Kế hoạch A chết, hãy bắt và chạy với Kế hoạch B ... Và nếu kế hoạch B thất bại, cuối cùng hãy sử dụng để khởi động Kế hoạch C, điều này sẽ khắc phục một trong các dịch vụ bị lỗi trong A hoặc B hoặc trang tôi.


0

Nó phụ thuộc vào ngôn ngữ và có thể vào việc thực hiện đang được sử dụng. Tiêu chuẩn trong C ++ là các ngoại lệ nên được lưu cho các sự kiện thực sự đặc biệt. Mặt khác, trong Python, một trong những hướng dẫn là " dễ xin tha thứ hơn là cho phép ", vì vậy việc tích hợp các khối thử / ngoại trừ trong logic chương trình được khuyến khích.


"Tiêu chuẩn trong C ++ là các ngoại lệ nên được lưu cho các sự kiện thực sự đặc biệt." Thật vô nghĩa. Ngay cả những người phát minh ra ngôn ngữ cũng không đồng ý với bạn .
arayq2

-1

Đó là một thói quen xấu, nhưng thỉnh thoảng tôi vẫn làm điều đó với trăn. Giống như thay vì kiểm tra xem một tập tin tồn tại tôi chỉ cần thử và xóa nó. Nếu nó ném một ngoại lệ, tôi bắt và chỉ cần biết rằng nó không ở đó. <== (không nhất thiết đúng nếu người dùng khác sở hữu tệp, nhưng tôi thực hiện nó trong thư mục chính của người dùng để điều này KHÔNG xảy ra).

Tuy nhiên, lạm dụng nó là một thực hành xấu.


3
Trong ví dụ đó, sử dụng các ngoại lệ thay vì "nhìn trước khi bạn nhảy" thực sự là một ý tưởng hay: Nó tránh được các điều kiện chủng tộc. Việc kiểm tra tính khả dụng của tệp (tồn tại, quyền, không bị khóa) thành công không có nghĩa là muộn hơn - ngay cả khi đó chỉ là một vài mã sau - truy cập (mở, xóa, di chuyển, khóa, bất cứ điều gì) sẽ thành công, vì tệp có thể được thay đổi (xóa, di chuyển, có quyền thay đổi) ở giữa.

Nếu con trăn đang ném một ngoại lệ chỉ vì một tập tin không tồn tại, thì nó dường như đang khuyến khích những thói quen xấu, như delnan mô tả.
Per Johansson

@delnan: Mặc dù đúng, IMHO nếu chạy trong điều kiện cuộc đua như vậy có khả năng, bạn nên suy nghĩ lại về thiết kế của mình. Trong trường hợp như vậy, rõ ràng có một sự tách biệt các mối quan tâm trong hệ thống của bạn. Trừ khi bạn có những lý do rất chính đáng để thực hiện mọi thứ theo cách đó, bạn nên thống nhất quyền truy cập vào cuối hoặc sử dụng cơ sở dữ liệu phù hợp để xử lý nhiều khách hàng đang cố gắng thực hiện các giao dịch trên cùng một dữ liệu liên tục.
back2dos

1
Đây không phải là một thói quen xấu. Đó là phong cách được đề xuất trong Python.
Winston Ewert

@ back2dos, bạn có thể ngăn chặn nó khi xử lý các tài nguyên bên ngoài như những người dùng khác của hệ thống cơ sở dữ liệu / tệp không?
Winston Ewert

-1

Tôi thích cách Apple định nghĩa nó: Ngoại lệ chỉ dành cho lỗi lập trình viên và lỗi thời gian chạy nghiêm trọng. Khác sử dụng mã lỗi. Nó giúp tôi quyết định khi nào nên sử dụng nó, tự nghĩ "Đây có phải là lỗi của lập trình viên khô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.