Đã kiểm tra vs Không được kiểm tra vs Không có Ngoại lệ Một cách thực hành tốt nhất về niềm tin trái ngược


10

Có nhiều yêu cầu cần thiết cho một hệ thống để truyền đạt và xử lý các trường hợp ngoại lệ đúng cách. Ngoài ra còn có nhiều tùy chọn cho một ngôn ngữ để lựa chọn để thực hiện khái niệm.

Yêu cầu cho các trường hợp ngoại lệ (không theo thứ tự cụ thể):

  1. Tài liệu : Một ngôn ngữ nên có ý nghĩa đối với các trường hợp ngoại lệ mà API có thể đưa ra. Lý tưởng nhất là phương tiện tài liệu này nên có thể sử dụng máy để cho phép trình biên dịch và IDE cung cấp hỗ trợ cho lập trình viên.

  2. Truyền các tình huống đặc biệt : Điều này là hiển nhiên, để cho phép một chức năng truyền đạt các tình huống ngăn chức năng được gọi thực hiện hành động dự kiến. Theo tôi có ba loại lớn của các tình huống như vậy:

    2.1 Lỗi trong mã khiến một số dữ liệu không hợp lệ.

    2.2 Các vấn đề trong cấu hình hoặc các tài nguyên bên ngoài khác.

    2.3 Tài nguyên vốn không đáng tin cậy (mạng, hệ thống tệp, cơ sở dữ liệu, người dùng cuối, v.v.). Đây là một chút của một trường hợp góc vì bản chất không đáng tin cậy của họ nên chúng ta mong đợi những thất bại lẻ tẻ của họ. Trong trường hợp này là những tình huống được coi là đặc biệt?

  3. Cung cấp đủ thông tin cho mã để xử lý nó : Các ngoại lệ nên cung cấp đủ thông tin cho callee để nó có thể phản ứng và có thể xử lý tình huống. thông tin cũng phải đủ để khi ghi nhật ký ngoại lệ này sẽ cung cấp đủ ngữ cảnh cho lập trình viên để xác định và cô lập các tuyên bố vi phạm và cung cấp giải pháp.

  4. Cung cấp niềm tin cho lập trình viên về trạng thái hiện tại của trạng thái thực thi mã của anh ta : Khả năng xử lý ngoại lệ của hệ thống phần mềm phải có mặt đủ để cung cấp các biện pháp bảo vệ cần thiết trong khi tránh xa lập trình viên để anh ta có thể tập trung vào nhiệm vụ tại tay.

Để bao quát những phương pháp sau đây đã được thực hiện bằng nhiều ngôn ngữ khác nhau:

  1. Các trường hợp ngoại lệ được kiểm tra Cung cấp một cách tuyệt vời để ghi lại các trường hợp ngoại lệ và về mặt lý thuyết khi được thực hiện đúng sẽ cung cấp sự đảm bảo chắc chắn rằng tất cả đều tốt. Tuy nhiên, chi phí cao đến mức nhiều người cảm thấy hiệu quả hơn khi chỉ cần bỏ qua bằng cách nuốt các ngoại lệ hoặc ném lại chúng như các ngoại lệ không được kiểm soát. Khi được sử dụng các trường hợp ngoại lệ được kiểm tra không phù hợp sẽ làm mất đi tất cả sự hữu ích của nó. Ngoài ra, các ngoại lệ được kiểm tra gây khó khăn cho việc tạo API ổn định về thời gian. Việc triển khai một hệ thống chung trong một miền cụ thể sẽ mang lại cho nó tình huống đặc biệt khó có thể duy trì bằng cách sử dụng các ngoại lệ được kiểm tra duy nhất.

  2. Các ngoại lệ không được kiểm tra - linh hoạt hơn nhiều so với ngoại lệ được kiểm tra, chúng không thể ghi lại đúng các tình huống đặc biệt có thể có của một triển khai nhất định. Họ dựa vào tài liệu đặc biệt nếu có. Điều này tạo ra các tình huống trong đó tính chất không đáng tin cậy của một phương tiện được che dấu bởi một API mang lại sự xuất hiện của độ tin cậy. Ngoài ra khi ném các ngoại lệ này mất đi ý nghĩa của chúng khi chúng di chuyển ngược lên qua các lớp trừu tượng. Vì chúng được ghi chép kém, một lập trình viên không thể nhắm mục tiêu chúng một cách cụ thể và thường cần phải tạo một mạng lưới rộng hơn nhiều so với mức cần thiết để đảm bảo rằng các hệ thống thứ cấp, nếu chúng thất bại, không làm hỏng toàn bộ hệ thống. Điều này đưa chúng ta trở lại với vấn đề nuốt phải kiểm tra ngoại lệ được cung cấp.

  3. Các kiểu trả về đa cấp Ở đây phải dựa vào một tập hợp rời rạc, tuple hoặc khái niệm tương tự khác để trả về kết quả mong đợi hoặc một đối tượng đại diện cho ngoại lệ. Ở đây không ngăn xếp ngăn xếp, không cắt mã, mọi thứ thực thi bình thường nhưng giá trị trả về phải được xác nhận lỗi trước khi tiếp tục. Tôi chưa thực sự làm việc với điều này vì vậy không thể nhận xét từ kinh nghiệm. Tôi thừa nhận rằng nó giải quyết được một số vấn đề ngoại lệ khi bỏ qua dòng chảy bình thường nhưng nó vẫn sẽ gặp phải nhiều vấn đề tương tự như các trường hợp ngoại lệ được kiểm tra là mệt mỏi và liên tục "vào mặt bạn".

Vì vậy, câu hỏi là:

Kinh nghiệm của bạn trong vấn đề này là gì và theo bạn, ứng cử viên tốt nhất để tạo ra một hệ thống xử lý ngoại lệ tốt cho một ngôn ngữ là gì?


EDIT: Vài phút sau khi viết câu hỏi này, tôi đã xem qua bài đăng này , ma quái!


2
"nó sẽ chịu nhiều vấn đề giống như các trường hợp ngoại lệ được kiểm tra là mệt mỏi và liên tục xuất hiện trên khuôn mặt của bạn": Không thực sự: với sự hỗ trợ ngôn ngữ phù hợp, bạn chỉ phải lập trình "con đường thành công", với bộ máy ngôn ngữ cơ bản đảm nhiệm việc truyền bá lỗi.
Giorgio

"Một ngôn ngữ nên có ý nghĩa để ghi lại các ngoại lệ mà API có thể đưa ra." - Midieel. Trong C ++, "chúng tôi" đã học được rằng điều này không thực sự hoạt động. Tất cả những gì bạn thực sự có thể làm là đưa ra liệu API có thể đưa ra bất kỳ ngoại lệ nào không . (Điều đó thực sự cắt ngắn một câu chuyện dài, nhưng tôi nghĩ rằng nhìn vào noexceptcâu chuyện trong C ++ có thể mang lại những hiểu biết rất tốt cho EH trong C # và Java.)
Martin Ba

Câu trả lời:


10

Trong những ngày đầu của C ++, chúng tôi đã phát hiện ra rằng không có một số loại lập trình chung chung, các ngôn ngữ được gõ mạnh là cực kỳ khó sử dụng. Chúng tôi cũng phát hiện ra rằng các ngoại lệ được kiểm tra và lập trình chung không hoạt động tốt với nhau và các ngoại lệ được kiểm tra về cơ bản bị bỏ rơi.

Các loại trả lại nhiều lần là tuyệt vời, nhưng không thay thế cho các trường hợp ngoại lệ. Không có ngoại lệ, mã đầy tiếng ồn kiểm tra lỗi.

Vấn đề khác với các ngoại lệ được kiểm tra là sự thay đổi trong các ngoại lệ được ném bởi một hàm cấp thấp buộc một loạt các thay đổi trong tất cả các người gọi và người gọi của họ, v.v. Cách duy nhất để ngăn chặn điều này là cho mỗi cấp mã để bắt bất kỳ trường hợp ngoại lệ nào được ném bởi các cấp thấp hơn và bọc chúng trong một ngoại lệ mới. Một lần nữa, bạn kết thúc với mã rất ồn ào.


2
Generics giúp giải quyết cả một nhóm lỗi mà phần lớn là do giới hạn của sự hỗ trợ của ngôn ngữ đối với mô hình OO. tuy nhiên, các lựa chọn thay thế dường như có mã mà chủ yếu là kiểm tra lỗi hoặc chạy với hy vọng các thông báo không bao giờ bị lỗi. Hoặc là bạn có những tình huống đặc biệt liên tục xuất hiện trên khuôn mặt của bạn hoặc sống trong một vùng đất mơ ước của những con thỏ lông trắng trở nên xấu xí thực sự khi bạn thả một con sói xấu lớn ở giữa!
Newtopian

3
+1 cho vấn đề xếp tầng. Bất kỳ hệ thống / kiến ​​trúc nào làm thay đổi khó khăn chỉ dẫn đến các hệ thống vá khỉ và lộn xộn, bất kể các tác giả có thiết kế tốt đến mức nào.
Matthieu M.

2
@Newtopian: Mẫu làm những việc không thể thực hiện theo hướng đối tượng nghiêm ngặt, chẳng hạn như cung cấp an toàn kiểu tĩnh cho các thùng chứa chung.
David Thornley

2
Tôi muốn thấy một hệ thống ngoại lệ với khái niệm "ngoại lệ được kiểm tra", nhưng một hệ thống rất khác với Java. Checked-ness không nên là một thuộc tính của một loại ngoại lệ , mà là ném các trang web, bắt các trang web và các trường hợp ngoại lệ; nếu một phương thức được quảng cáo là ném ngoại lệ được kiểm tra, thì sẽ có hai tác dụng: (1) chức năng sẽ xử lý "ném" ngoại lệ được kiểm tra bằng cách thực hiện một thao tác đặc biệt nào đó (ví dụ: đặt cờ mang, v.v. tùy thuộc vào nền tảng chính xác) mà mã cuộc gọi sẽ được yêu cầu phải được chuẩn bị cho.
supercat

7
"Không có ngoại lệ, mã chứa đầy tiếng ồn kiểm tra lỗi.": Tôi không chắc về điều này: trong Haskell bạn có thể sử dụng các đơn vị cho việc này và tất cả tiếng ồn kiểm tra lỗi đã biến mất. Tiếng ồn được giới thiệu bởi "các loại trả về đa cấp" là một hạn chế của ngôn ngữ lập trình hơn là bản thân giải pháp.
Giorgio

9

Trong một thời gian dài các ngôn ngữ OO, việc sử dụng các ngoại lệ là tiêu chuẩn không chính thức để giao tiếp lỗi. Nhưng các ngôn ngữ lập trình chức năng cung cấp khả năng của một cách tiếp cận khác, ví dụ như sử dụng các đơn nguyên (mà tôi chưa sử dụng) hoặc "Lập trình định hướng đường sắt" nhẹ hơn, như được mô tả bởi Scott Wlaschin.

Nó thực sự là một biến thể của loại kết quả đa cấp.

  • Hàm trả về thành công hoặc lỗi. Nó không thể trả về cả hai (như trường hợp với một tuple).
  • Tất cả các lỗi có thể đã được ghi lại một cách ngắn gọn (Ít nhất là trong F # với các loại kết quả là các hiệp hội bị phân biệt đối xử).
  • Người gọi không thể sử dụng kết quả mà không xem xét nếu kết quả là thành công hay thất bại.

Loại kết quả có thể được khai báo như thế này

type Result<'TSuccess,'TFail> =
| Success of 'TSuccess
| Fail of 'TFail

Vì vậy, kết quả của một hàm trả về loại này sẽ là một Successhoặc một Failloại. Nó không thể là cả hai.

Trong các ngôn ngữ lập trình định hướng bắt buộc hơn, loại phong cách này có thể yêu cầu một lượng lớn mã trên trang web của người gọi. Nhưng lập trình chức năng cho phép bạn xây dựng các hàm hoặc toán tử liên kết để liên kết nhiều hàm với nhau để kiểm tra lỗi không chiếm một nửa mã. Ví dụ:

// Create an updateUser function that takes an id, and new state
// as input, and updates an existing user.
let updateUser id input =
    validateInput input
    >>= loadUser id
    >>= updateUser input
    >>= saveUser id
    >>= notifyAboutUserUpdated

Các updateUserchức năng gọi mỗi một trong các chức năng liên tiếp, và mỗi người trong số họ có thể thất bại. Nếu tất cả đều thành công, kết quả của hàm được gọi cuối cùng được trả về. Nếu một trong các chức năng thất bại, thì kết quả của chức năng đó sẽ là kết quả của updateUserchức năng tổng thể . Tất cả điều này được xử lý bởi toán tử tùy chỉnh >> =.

Trong ví dụ trên, các loại lỗi có thể là

type UserValidationErrorType =
| InvalidEmail of string
| MissingFirstName of string
... etc

type DbErrorType =
| RecordNotFound of int
| ConcurrencyError of int

type UpdateUserErrorType =
| InvalidInput of UserValidationErrorType
| DbError of DbErrorType

Nếu người gọi của updateUserkhông xử lý rõ ràng tất cả các lỗi có thể từ hàm, trình biên dịch sẽ đưa ra cảnh báo. Vì vậy, bạn có tất cả mọi thứ tài liệu.

Trong Haskell, có một doký hiệu có thể làm cho mã thậm chí sạch hơn.


2
Câu trả lời và tài liệu tham khảo rất tốt (lập trình hướng đường sắt), +1. Bạn có thể muốn đề cập đến doký hiệu của Haskell , làm cho mã kết quả thậm chí còn sạch hơn.
Giorgio

1
@Giorgio - Tôi đã làm bây giờ, nhưng tôi chưa làm việc với Haskell, chỉ có F #, vì vậy tôi thực sự không thể viết nhiều về nó. Nhưng bạn có thể thêm vào câu trả lời nếu bạn muốn.
Pete

Cảm ơn, tôi đã viết một ví dụ nhỏ nhưng vì nó không đủ nhỏ để thêm vào câu trả lời của bạn nên tôi đã viết một câu trả lời hoàn chỉnh (có thêm một số thông tin cơ bản).
Giorgio

2
Chính Railway Oriented Programmingxác là hành vi đơn nguyên.
Daenyth

5

Tôi thấy câu trả lời của Pete rất hay và tôi muốn thêm một số xem xét và một ví dụ. Một cuộc thảo luận rất thú vị về việc sử dụng các ngoại lệ so với trả về các giá trị lỗi đặc biệt có thể được tìm thấy trong Lập trình trong ML tiêu chuẩn, bởi Robert Harper , ở cuối Phần 29.3, trang 243, 244.

Vấn đề là để thực hiện một phần chức năng ftrả về một giá trị của một số loại t. Một giải pháp là có chức năng có loại

f : ... -> t

và ném một ngoại lệ khi không có kết quả có thể. Giải pháp thứ hai là thực hiện một hàm với kiểu

f : ... -> t option

và trở lại SOME vthành công, và NONEthất bại.

Đây là văn bản từ cuốn sách, với sự điều chỉnh nhỏ do chính tôi tạo ra để làm cho văn bản tổng quát hơn (cuốn sách đề cập đến một ví dụ cụ thể). Các văn bản sửa đổi được viết bằng chữ in nghiêng .

Sự đánh đổi giữa hai giải pháp là gì?

  1. Giải pháp dựa trên các loại tùy chọn làm cho rõ ràng trong loại chức fnăng có khả năng thất bại. Điều này buộc lập trình viên phải kiểm tra rõ ràng sự thất bại bằng cách sử dụng phân tích trường hợp về kết quả của cuộc gọi. Trình kiểm tra loại sẽ đảm bảo rằng người ta không thể sử dụng t optionở nơit dự kiến. Giải pháp dựa trên các trường hợp ngoại lệ không chỉ ra rõ ràng sự thất bại trong loại của nó. Tuy nhiên, lập trình viên vẫn bị buộc phải xử lý lỗi, vì nếu không, một lỗi ngoại lệ chưa được xử lý sẽ được đưa ra trong thời gian chạy, thay vì thời gian biên dịch.
  2. Giải pháp dựa trên các loại tùy chọn yêu cầu phân tích trường hợp rõ ràng về kết quả của mỗi cuộc gọi. Nếu hầu hết các kết quả của thành công thì thành công, việc kiểm tra là dư thừa và do đó quá tốn kém. Giải pháp dựa trên các trường hợp ngoại lệ là không có chi phí này: nó thiên về trường hợp bình thường của Keith về việc trả lại một t, thay vì trường hợp không thành công trong các trường hợp không trả về kết quả . Việc thực hiện các ngoại lệ đảm bảo rằng việc sử dụng trình xử lý hiệu quả hơn so với phân tích trường hợp rõ ràng trong trường hợp thất bại là hiếm so với thành công.

[cắt] Nói chung, nếu hiệu quả là tối quan trọng, chúng ta có xu hướng thích các ngoại lệ nếu thất bại là hiếm, và thích các tùy chọn nếu thất bại là tương đối phổ biến. Mặt khác, nếu kiểm tra tĩnh là tối quan trọng, thì việc sử dụng các tùy chọn là thuận lợi vì trình kiểm tra loại sẽ thực thi yêu cầu mà lập trình viên kiểm tra lỗi, thay vì chỉ phát sinh lỗi trong thời gian chạy.

Điều này theo như sự lựa chọn giữa các trường hợp ngoại lệ và các loại trả về tùy chọn có liên quan.

Liên quan đến ý tưởng đại diện cho một lỗi trong kiểu trả về dẫn đến kiểm tra lỗi lan truyền khắp mã: điều này không cần phải là trường hợp. Dưới đây là một ví dụ nhỏ trong Haskell minh họa điều này.

Giả sử chúng ta muốn phân tích hai số và sau đó chia số thứ nhất cho số thứ hai. Vì vậy, có thể có một lỗi trong khi phân tích từng số hoặc khi chia (chia cho số không). Vì vậy, chúng tôi phải kiểm tra lỗi sau mỗi bước.

import Text.Read

parseInt :: String -> Maybe Int
parseInt s = readMaybe s :: Maybe Int

safeDiv :: Int -> Int -> Maybe Int
safeDiv n d = if d /= 0 then Just (n `div` d) else Nothing

toString :: Maybe Int -> String
toString (Just i) = show i
toString Nothing  = "error"

main = do
         -- Get two lines from the terminal.
         nStr <- getLine
         dStr <- getLine

         -- Parse each string and divide.
         let r = do n <- parseInt nStr
                    d <- parseInt dStr
                    safeDiv n d

         -- Print the result.
         putStrLn $ toString r

Việc phân tích cú pháp và phân chia được thực hiện trong let ...khối. Lưu ý rằng bằng cách sử dụng Maybeđơn nguyên và doký hiệu, chỉ có đường dẫn thành công được chỉ định: ngữ nghĩa của Maybeđơn vị ngầm truyền bá giá trị lỗi ( Nothing). Không có chi phí cho lập trình viên.


2
Tôi nghĩ rằng trong những trường hợp như thế này khi bạn muốn in một loại thông báo lỗi hữu ích, Eitherloại này sẽ phù hợp hơn. Bạn sẽ làm gì nếu bạn đến Nothingđây? Bạn chỉ nhận được thông báo "lỗi". Không hữu ích cho việc gỡ lỗi.
sara

1

Tôi đã trở thành một fan hâm mộ lớn của Ngoại lệ được kiểm tra và tôi muốn chia sẻ quy tắc chung của mình về thời điểm sử dụng chúng.

Tôi đã đi đến kết luận rằng về cơ bản có 2 loại lỗi mà mã của tôi phải xử lý. Có những lỗi có thể kiểm tra được trước khi mã thực thi và có những lỗi không thể kiểm tra được trước khi mã thực thi. Một ví dụ đơn giản cho một lỗi có thể kiểm tra được trước khi mã được thực thi trong NullPulumException.

//... bad code below.  the runnable variable
// tries to call the run() method before the variable
// is instantiated.  Running the code below will cause
// a NullPointerException.
Runnable runnable = null;
runnable.run();

Một thử nghiệm đơn giản có thể tránh được lỗi như ...

Runnable runnable = null;
...
if (runnable != null)
{   runnable.run(); }

Đôi khi trong điện toán, bạn có thể chạy 1 hoặc nhiều bài kiểm tra trước khi thực thi mã để đảm bảo an toàn VÀ BẠN S ST VẪN NHẬN ĐƯỢC MỘT VẤN ĐỀ. Ví dụ: bạn có thể kiểm tra một hệ thống tệp để đảm bảo có đủ dung lượng đĩa trên ổ cứng trước khi bạn ghi dữ liệu vào ổ đĩa. Trong một hệ điều hành đa xử lý, chẳng hạn như các hệ điều hành được sử dụng ngày nay, quy trình của bạn có thể kiểm tra dung lượng ổ đĩa và hệ thống tệp sẽ trả về một giá trị cho biết có đủ dung lượng, sau đó chuyển đổi ngữ cảnh sang quy trình khác có thể ghi các byte còn lại có sẵn cho hoạt động hệ thống. Khi bối cảnh hệ điều hành chuyển trở lại quy trình đang chạy của bạn nơi bạn ghi nội dung của mình vào đĩa, một ngoại lệ sẽ xảy ra đơn giản vì không có đủ dung lượng đĩa trên hệ thống tệp.

Tôi coi kịch bản trên là một trường hợp hoàn hảo cho Ngoại lệ được kiểm tra. Đó là một ngoại lệ trong mã buộc bạn phải đối phó với điều gì đó xấu mặc dù mã của bạn có thể được viết hoàn hảo. Nếu bạn chọn làm những điều xấu như 'nuốt ngoại lệ', bạn là lập trình viên tồi. Nhân tiện, tôi đã tìm thấy những trường hợp hợp lý khi nuốt ngoại lệ nhưng xin vui lòng để lại nhận xét trong mã về lý do tại sao ngoại lệ bị nuốt. Cơ chế xử lý ngoại lệ không đáng trách. Tôi thường nói đùa rằng tôi thích máy tạo nhịp tim của mình được viết bằng một ngôn ngữ đã kiểm tra Ngoại lệ.

Có những lúc nó trở nên khó khăn để quyết định xem mã có thể kiểm tra được hay không. Ví dụ: nếu bạn đang viết một trình thông dịch và SyntaxException sẽ bị ném khi mã không thực thi vì một số lý do cú pháp, thì SyntaxException nên là Ngoại lệ được kiểm tra hay (trong Java) là RuntimeException? Tôi sẽ trả lời nếu trình thông dịch kiểm tra cú pháp của mã trước khi mã được thực thi thì Exception sẽ là RuntimeException. Nếu trình thông dịch chỉ đơn giản chạy mã 'nóng' và chỉ đơn giản là gặp lỗi Cú pháp, tôi sẽ nói ngoại lệ phải là Ngoại lệ được kiểm tra.

Tôi sẽ thừa nhận rằng tôi không phải lúc nào cũng vui khi phải bắt hoặc ném Ngoại lệ đã kiểm tra vì có những lúc tôi không biết phải làm gì. Các trường hợp ngoại lệ được kiểm tra là một cách để buộc một lập trình viên phải chú ý đến vấn đề tiềm ẩn có thể xảy ra. Một trong những lý do tại sao tôi lập trình trong Java là vì nó đã kiểm tra ngoại lệ.


1
Tôi muốn nói đúng hơn là máy điều hòa nhịp tim của tôi được viết bằng một ngôn ngữ hoàn toàn không có ngoại lệ và tất cả các dòng mã đều xử lý lỗi thông qua mã trả về. Khi bạn ném một ngoại lệ, bạn đang nói "tất cả đã sai" và cách an toàn duy nhất để tiếp tục xử lý là dừng và khởi động lại. Một chương trình dễ dàng kết thúc ở trạng thái không hợp lệ không phải là thứ bạn muốn cho phần mềm quan trọng (và Java rõ ràng không cho phép sử dụng phần mềm quan trọng trong EULA)
gbjbaanb

Sử dụng ngoại lệ và không kiểm tra chúng so với sử dụng mã trả về và không kiểm tra chúng cuối cùng, tất cả đều mang lại kết quả ngừng tim giống nhau.
Newtopian

-1

Tôi hiện đang ở giữa một dự án / API dựa trên OOP khá lớn và tôi đã sử dụng bố cục của các ngoại lệ này. Nhưng tất cả thực sự phụ thuộc vào mức độ bạn muốn đi sâu với việc xử lý ngoại lệ và tương tự.

ExpectedException
- AuthorisedException
- EmptysetException
- NoRemainedException
- NoRowsException
- NotFoundException
- ValidationException

UnazedException
- ConnectivityException
- Môi trường ngoại lệ
- Lập trình ngoại lệ
- SQLException

THÍ DỤ

   $valid_types = array('mysql', 'oracle', 'sqlite');
       if (!in_array($type, $valid_types)) {
           throw new ecProgrammerException(
        'The database type specified, %1$s, is invalid. Must be one of: %2$s.',
    $type,
    join(', ', $valid_types)
    );
}

11
Nếu ngoại lệ được mong đợi, nó không thực sự là một ngoại lệ. "NoRowsException"? Âm thanh như dòng điều khiển đối với tôi, và do đó sử dụng ngoại lệ kém.
quentin-starin

1
@qes: Sẽ có ý nghĩa khi đưa ra một ngoại lệ bất cứ khi nào một hàm không thể tính được một giá trị, ví dụ: double Math.sqrt (double v) hoặc User findUser (id dài). Điều này cho phép người gọi tự do bắt và xử lý các lỗi khi thuận tiện, thay vì kiểm tra sau mỗi cuộc gọi.
kevin cline

1
Dự kiến ​​= kiểm soát luồng = chống mẫu ngoại lệ. Ngoại lệ không nên được sử dụng cho dòng điều khiển. Nếu nó được dự kiến ​​sẽ tạo ra lỗi cho đầu vào cụ thể, thì nó chỉ được thông qua một phần của giá trị trả về. Vì vậy, chúng tôi có NANhoặc NULL.
Eonil

1
@Eonil ... hoặc Tùy chọn <T>
Maarten Bodewes
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.