Tại sao Tùy chọn / Có thể được coi là một ý tưởng tốt và ngoại lệ được kiểm tra không?


23

Một số ngôn ngữ lập trình như Scala có khái niệm về các Optionloại (còn được gọi là Maybe), có thể chứa giá trị hoặc không.

Từ những gì tôi đã đọc về họ, họ được coi là một cách xử lý vấn đề vượt trội hơn null, bởi vì họ rõ ràng buộc lập trình viên phải xem xét các trường hợp có thể không có giá trị thay vì chỉ nổ tung trong thời gian chạy.

Mặt khác, các trường hợp ngoại lệ được kiểm tra trong Java dường như bị coi là một ý tưởng tồi và Java dường như là ngôn ngữ được sử dụng rộng rãi duy nhất thực hiện chúng. Nhưng ý tưởng đằng sau chúng dường như có phần giống với Optionloại, để rõ ràng buộc lập trình viên phải đối phó với thực tế là một ngoại lệ có thể bị ném.

Có một số vấn đề khác với các Ngoại lệ được kiểm tra mà Optioncác loại không có? Hoặc những ý tưởng này không giống như tôi nghĩ, và có những lý do chính đáng để buộc xử lý rõ ràng cho Tùy chọn và không cho Ngoại lệ?


Cũng xem Either e akiểu dữ liệu.

4
Về các trường hợp ngoại lệ được kiểm tra: với tư cách là người sử dụng vô số các lib Java nguồn mở và nội bộ với cơ sở mã đang phát triển và các tài liệu bị thiếu / lỗi thời, tôi rùng mình khi nghĩ rằng Java sẽ không thực thi một số ngoại lệ nhất định phải được tuyên bố rõ ràng. Nó sẽ là một cơn ác mộng của các lỗi thời gian chạy chưa được xử lý xuất hiện ở những nơi xấu, bất ngờ. Và Java7 cuối cùng đã xử lý ngoại lệ gần như lành mạnh, loại bỏ phần lớn sự lộn xộn thử bắt cũ.
hyde

Câu trả lời:


24

Bởi vì Options là composable. Có rất nhiều phương pháp hữu ích trên Optioncho phép bạn viết mã ngắn gọn, trong khi vẫn cho phép điều khiển chính xác trên dòng chảy: map, flatMap, toList, flattenvà nhiều hơn nữa. Điều này là do thực tế Optionlà một loại đơn nguyên đặc biệt, một số đối tượng mà chúng ta biết rất rõ cách sáng tác. Nếu bạn không có các phương thức này và phải luôn khớp mẫu Optionhoặc gọi isDefinedthường xuyên, chúng sẽ không hữu ích.

Thay vào đó, trong khi các trường hợp ngoại lệ được kiểm tra có thêm một số an toàn, bạn không thể làm gì nhiều với chúng ngoài việc bắt chúng hoặc để chúng nổi bong bóng lên (với bảng kê khai được thêm vào trong khai báo kiểu).


1
Các trường hợp ngoại lệ được kiểm tra sáng tác theo cách ít nhiều giống nhau ... Sự khác biệt giữa try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)chính xác là gì? Khác với thực tế là trước đây cung cấp cho bạn nhiều chi tiết hơn về những gì đã sai.
dùng253751

14

Trong khi có liên quan, ngoại lệ và các đối tượng Có thể không giải quyết cùng loại vấn đề.

Ngoại lệ

Các ngoại lệ thực sự tỏa sáng khi bạn phải xử lý một tình huống không cục bộ với một tình huống đặc biệt (trong một số trường hợp xảy ra là một lỗi). Ví dụ: bạn đang phân tích một csv và muốn tự bảo vệ mình trước các dòng có định dạng sai. Nơi mà bạn thấy có gì đó không đúng có thể là một số hàm gọi đi từ đường lặp. Nếu bạn ném một ngoại lệ ở mức sâu nhất (nơi bạn tìm hiểu về vấn đề định dạng), bạn có thể bắt nó trong vòng lặp, ghi lại lỗi và chuyển sang dòng tiếp theo. Bạn không phải sửa đổi bất cứ điều gì trong phần còn lại của mã.

Kiểm tra ngoại lệ thêm rất nhiều đau đớn vì tất cả các chức năng trung gian phải khai báo loại có thể ném. Tính năng đánh bại mục đích ban đầu, đó là lý do tại sao ngày nay chúng không phổ biến.

Có thể đồ vật

Có lẽ các đối tượng nên được chọn khi bạn có thể xử lý cục bộ với một "thất bại". Theo nghĩa đó, chúng là sự thay thế cho mã trả về + chuyển qua api tham chiếu hoặc loại không thể.

Ưu điểm của đối tượng Có thể là bạn tuyên bố rõ ràng rằng có điều gì đó có thể sai. Trong haskell, một đối tượng không có thể phải có một giá trị, nếu không thì chương trình sẽ không được biên dịch.

Vấn đề với các loại nullable là bạn phải kiểm tra null mọi lúc để an toàn tuyệt đối. Trạng thái "có thể sai" là trạng thái mặc định.

Vấn đề với mã trả lại + vượt qua ref apis là hầu hết mọi người đều khó đọc hơn.


1
@MattFenwick cảm ơn bạn đã phản hồi. Tại sao bạn nghĩ rằng ví dụ csv không có ý nghĩa? OP không thực sự yêu cầu các kỹ thuật tránh nồi hơi và tôi có cảm giác rằng các từ vựng như functor & monads ứng dụng có thể quá kỹ thuật cho câu hỏi này.
Simon Bergot

1
Tôi muốn chỉ ra rằng, với Java (không chắc chắn về các ngôn ngữ khác có ngoại lệ được kiểm tra), IDE sẽ chăm sóc thêm và cắt tỉa các cú ném và cập nhật phần soạn thảo javadoc. Vì vậy, ít nhất phần đó là không bận tâm và chắc chắn không có đau đớn. Cho dù đó là một nỗi đau hay lợi ích hay điều gì đó ở giữa khi thực hiện thiết kế API, đó là một vấn đề khác ...
hyde 29/03/13

5
@hyde: Chỉ vì một IDE có thể tự động hóa thế hệ nồi hơi vô nghĩa không có nghĩa là nồi hơi vô nghĩa không phải là một nỗi đau.
Michael Shaw

2
@hyde: Nhưng nỗi đau không được xóa bỏ. Cái nồi hơi vô nghĩa vẫn còn đó, làm lộn xộn mã không có lý do. Nếu có một lý do cho nồi hơi, nó là gì?
Michael Shaw

2
@MichaelShaw Nếu ngoại lệ là vô nghĩa, hãy xóa nó: bỏ qua tình huống hoặc trả về giá trị lỗi thay thế. Nếu đó là một lỗi hoặc tình huống không thể phục hồi: sử dụng ngoại lệ không được kiểm tra. Những gì còn lại cũng quan trọng như ví dụ các loại tham số, không phải là bản tóm tắt vô nghĩa. Nếu đó là API xấu trong lib hiện tại, hãy xem xét phương thức / lớp trình bao bọc, sử dụng lib khác hoặc chỉ chịu đựng API xấu.
hyde

1

bởi vì với Maybebạn có thể trì hoãn xử lý lỗi cho đến khi bạn thực sự cần giá trị (có thể là một vài cuộc gọi phương thức)

trong khi ngoại lệ được kiểm tra cần được xử lý tại vị trí cuộc gọi

mặt trái duy nhất của ngoại lệ là có nhiều thông tin hơn có thể được thông qua về lý do tại sao nó thất bại (trừ khi ai đó phát triển một trường MaybeErrorcó thể ném được khi có lỗi)


2
Nhưng tôi có thể trì hoãn việc xử lý ngoại lệ được kiểm tra bằng cách tuyên bố rằng phương thức của tôi ném ngoại lệ này.
Nhà khoa học điên

1
@MadSellectist chỉ đi lên ngăn xếp cuộc gọi, trong khi Có thể có thể đi theo mọi hướng
ratchet freak

5
Tôi nghĩ bạn không nên nhầm lẫn Maybecác loại với xử lý lỗi. Một ngoại lệ được sử dụng để báo cáo lỗi, một loại tùy chọn được sử dụng để thể hiện kết quả của một phần chức năng. Hàm trả về một phần Nothingkhông phải là lỗi.
Giorgio

@MadSellectist: Nếu một lệnh gọi phương thức trả về một dấu hiệu "Giá trị không hợp lệ", câu lệnh ngay sau khi nó có thể thực thi. Ngược lại, nếu một phương thức đưa ra một ngoại lệ không được bắt ngay lập tức, câu lệnh theo sau cuộc gọi sẽ bị bỏ qua. Để các ngoại lệ được kiểm tra làm mờ đi ngăn xếp cuộc gọi nói chung là xấu (và không nên là cách 'dễ dàng nhất' để đối phó với chúng) vì không có cách nào để người gọi biết liệu điều kiện đó có đúng với phương thức mà nó gọi hay không cho dù nó đại diện cho một điều kiện bất ngờ mà phương thức được gọi là cho phép bong bóng lên.
supercat
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.