Nó không phải là một thực hành tốt để xử lý các ngoại lệ thời gian chạy trong mã?


11

Tôi đang làm việc trên một ứng dụng Java và tôi thấy rằng các ngoại lệ thời gian chạy được xử lý ở nhiều nơi. Ví dụ,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

Câu hỏi của tôi là, khi nào thì nên xử lý ngoại lệ Runtime? Khi nào nên để lại ngoại lệ?


7
-1: Không có câu trả lời duy nhất cho câu hỏi này rộng và mơ hồ. Không thể đưa ra một câu trả lời duy nhất cho một câu hỏi không tập trung như thế này. Câu hỏi này thật kinh khủng. Vui lòng cung cấp các ví dụ cụ thể về nơi bạn có nghi ngờ.
S.Lott

@ S.Lott Tôi không đồng ý trong trường hợp này vì dường như có một tập hợp các lập trình viên có trong đầu rằng đây là trường hợp không có tính hợp lý "Tốt".
SoylentGray

2
@Chad: "đây là trường hợp không có tính hợp lý" Tốt ". Điều đó có thể đúng. Nhưng câu trả lời duy nhất có thể là "nó phụ thuộc". Do đó, câu hỏi có vẻ bị lỗi.
S.Lott

Câu trả lời:


18

Nó phụ thuộc.

Ví dụ: Integer#parseIntném NumberFormatException(là RTE) nếu chuỗi được cung cấp không thể được phân tích cú pháp. Nhưng chắc chắn bạn không muốn ứng dụng của mình bị sập chỉ vì người dùng đã viết "x" vào trường văn bản dành cho số nguyên? Và làm thế nào để bạn biết liệu chuỗi có thể được phân tích cú pháp, trừ khi bạn cố gắng phân tích cú pháp trước? Vì vậy, trong trường hợp này, RTE chỉ là một tín hiệu lỗi sẽ gây ra một số loại thông báo lỗi. Người ta có thể lập luận rằng đó phải là một ngoại lệ được kiểm tra, nhưng bạn có thể làm gì - không phải vậy.


2
Tôi đồng ý với "Nó phụ thuộc", nhưng ví dụ phân tích cú pháp của bạn dường như là một trường hợp thiết kế API tồi. Integer#parseIntnên thực sự trả lại một Maybe<Integer>thay thế và không ném bất kỳ ngoại lệ nào cả.
Jörg W Mittag

3
@ Jorg W Mittag: Tôi đồng ý rằng đó là thiết kế API tồi, nhưng đó là thế giới thực mà chúng ta phải đối phó. Làm thế nào để xử lý đúng đắn throwables / giá trị trả lại phụ thuộc vào cách thế giới thực sự làm việc, chứ không phải về cách nó một cách tối ưu nên làm việc :-)
Joonas Pulakka

Vấn đề ở đây là, bạn có thể làm điều gì đó có ý nghĩa cho một điều kiện dự đoán (đầu vào của người dùng không phải là số nguyên). Chỉ cần nuốt NPE là phong cách xấu và sẽ chỉ che đậy các lỗi lập trình hiện có.
Jürgen Strobel

7

NullPulumExceptions thường là dấu hiệu của một kiểm tra null bị thiếu. Vì vậy, thay vì bắt nó như thế này, bạn nên thêm kiểm tra null phù hợp để đảm bảo không ném ngoại lệ.

Nhưng đôi khi, nó là thích hợp để xử lý RunTimeExceptions. Ví dụ: khi bạn không thể sửa đổi mã để thêm kiểm tra null tại địa điểm thích hợp hoặc khi ngoại lệ là một thứ gì đó không phải là NullPulumException.

Ví dụ của bạn về xử lý ngoại lệ là khủng khiếp. Làm như vậy, bạn mất dấu vết ngăn xếp và thông tin chính xác về vấn đề. Và bạn thực sự không giải quyết nó vì có thể bạn sẽ kích hoạt một NullPulumException khác ở một nơi khác và nhận thông tin sai lệch về những gì đã xảy ra và cách giải quyết nó.


1
Tôi muốn thêm rằng kiểm tra null là một quyết định hiệu quả tốt hơn.
Mahmoud Hossam

... Tuy nhiên, nếu bạn đang thực hiện hàng tá phân bổ "không bao giờ thất bại" ở một nơi, việc thêm kiểm tra null cho mỗi trong số chúng có thể làm xáo trộn mã một cách lố bịch. Một ngoại lệ bắt tất cả (SILL xử lý tình huống một cách duyên dáng, không chỉ return null;) sẽ là một giải pháp tốt hơn.
SF.

Bạn có thể đang nhầm lẫn java với một cái gì đó khác (C ++ cho ví dụ). Khi phân bổ thất bại, bạn nhận được OutOfMemoryError hoặc một cái gì đó tương tự, không bao giờ là một con trỏ null. Thay đổi một trả về null thay vì một ngoại lệ đang che giấu lỗi chờ mã phát nổ ở một nơi khác.
deadalnix

newném std::bad_alloctrong C ++.
R. Martinho Fernandes

Giả sử rằng toán tử mới không bị quá tải, đó là thông lệ. Trong C ++, bất cứ điều gì cũng có thể xảy ra;) Nhưng OK, giả sử malloc của C. Điểm quan trọng là bạn không bao giờ có được điều đó trong java.
deadalnix

4

Tôi xử lý các trường hợp ngoại lệ dự kiến ​​nơi tôi mong đợi chúng. (Giống như lỗi đọc / ghi DB). Trường hợp ngoại lệ bất ngờ tôi bong bóng lên. Một nơi nào khác có thể đang mong đợi ngoại lệ và có logic cho nó.


2

Ngoại lệ chỉ nên là .. ngoại lệ. Thực hành tốt nhất khi sử dụng các ngoại lệ là sử dụng chúng để bao quát tình huống trong đó điều gì đó trái ngược với những gì bạn sẽ xảy ra. Ví dụ kinh điển là FileNotFoundException sẽ bị ném khi một tệp đơn giản là không có ở đó. Nếu bạn đang kiểm tra sự tồn tại của tệp, thì bạn sử dụng File.exists () vì bạn chỉ đơn giản là dùng một cây gậy 10 chân để xem bạn có đánh thứ gì không.

Về mặt kỹ thuật, bạn có thể hoàn thành các kết quả tương tự bằng cách bao quanh nó trong một lần thử và sử dụng tệp như thể nó tồn tại, nhưng các ngoại lệ A) thường tốn kém về tài nguyên và các lập trình viên sẽ cho rằng bạn có nghĩa là tệp tồn tại nếu nó tồn tại trong một thử bắt, làm tăng thêm sự nhầm lẫn chung của một chương trình.

Có nhiều tình huống trong đó tôi sẽ viết một phương thức lấy một số giá trị từ cơ sở dữ liệu. Một ngàn điều có thể sai, và xem làm thế nào tôi chỉ cần một mẩu thông tin nhỏ, thật bất tiện khi bao quanh cuộc gọi với một danh sách thử bắt có 5 trường hợp ngoại lệ khác nhau. Vì vậy, tôi sẽ bắt ngoại lệ trong phương thức tìm nạp. Nếu có lỗi xảy ra, tôi thực hiện bất kỳ hành động thích hợp nào để đóng kết nối cơ sở dữ liệu hoặc không có gì trong mệnh đề cuối cùng và trả về null. Đây là cách thực hành tốt không chỉ vì nó đơn giản hóa mã của bạn mà còn bởi vì "null" gửi cùng một thông điệp mà bạn có thể nhận được từ một ngoại lệ .. rằng một cái gì đó đã không đi theo kế hoạch. Quản lý các chi tiết cụ thể ngoại lệ trong phương thức tìm nạp, nhưng quản lý những việc cần làm khi mọi thứ không '

Ví dụ:

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}

6
Nếu bạn sử dụng File.exists () và dựa vào kết quả, điều kiện cuộc đua có thể xảy ra nếu tệp bị xóa ngay giữa File.exists () và File.open (). Nếu điều này gây ra lỗi nghiêm trọng về bảo mật, kẻ tấn công có thể gây ra tình trạng này trên mục đích. Bởi vì điều này, đôi khi tốt hơn là giữ nguyên tử hoạt động, tức là thử nó và bắt ngoại lệ.
user281377

1
Ngoài ra, có những tệp phải tồn tại để chạy ứng dụng. Đó sẽ là những điều kiện đặc biệt. Nếu có một tệp mà bạn phải có để ứng dụng hoạt động, thì không có lý do gì để không đọc từ đó và sau đó xử lý ngoại lệ cho trường hợp ngoại lệ. Tôi tin rằng nó làm cho ý định rõ ràng hơn.
Thomas Owens

Đây là một quyết định tồi để trả về null. Nó sẽ dẫn đến NullPulumException tại một số điểm và sẽ rất khó để gỡ lỗi những gì đã sai. Bởi vì ai đó SILL tại một số điểm quên kiểm tra null.
deadalnix

@deadalnix: Tôi có thể lập luận rằng bạn có thể dễ dàng quên đi việc bao quanh bằng một thử bắt khác. Sự khác biệt là một vấn đề về phong cách, không phải chức năng.
Neil

@ammoQ: Tôi không đồng ý. Tôi nghĩ bạn nên sử dụng File.exists () và trong trường hợp hiếm hoi nó bị xóa trước khi bạn sử dụng nó, một ngoại lệ là phù hợp hơn. Sự khác biệt là nơi bạn giữ được đánh bắt của bạn. Đơn giản chỉ cần có một công cụ bắt ngoại lệ chăn cho các lỗi không lường trước được để đăng nhập và báo cáo nó.
Neil

-5

vâng, bạn đang xử lý chính xác các ngoại lệ về thời gian chạy không phải là một cách thực hành tốt. Lý do là nó được coi là tốn kém / tốn bộ nhớ.


5
Hi prassee, bạn có thể giải thích về câu trả lời của bạn? Một lớp lót không được hỗ trợ với các sự kiện, tài liệu tham khảo hoặc kinh nghiệm không hữu ích.
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.