Làm thế nào để đối phó với các ngoại lệ được kiểm tra mà không bao giờ có thể được ném


35

Thí dụ:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

Vì mã hóa được mã hóa cứng và chính xác, nên hàm tạo sẽ không bao giờ ném UnsupportedEncodingException được khai báo trong đặc tả (trừ khi triển khai java bị hỏng, trong trường hợp đó tôi vẫn bị mất). Dù sao, Java buộc tôi phải đối phó với ngoại lệ đó.

Hiện tại, có vẻ như thế

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

Bất kỳ ý tưởng làm thế nào để làm cho nó tốt hơn?


4
Đối với một thử thách thực sự, hãy viết một bài kiểm tra đơn vị để đảm bảo rằng sản phẩm này thực sự hoạt động.
Jay Elston

1
`ném ImpossibleException mới (" Khởi động lại vũ trụ. Mọi thứ đang rối tung lên ", e);
Chris Cudmore

1
"Sẽ không bao giờ xảy ra" sẽ ...

Thorbjørn Ravn Andersen: có thể sau khi thay đổi chương trình, nhưng ít nhất ở trạng thái hiện tại, không có tập hợp dữ liệu đầu vào nào có thể kích hoạt ngoại lệ.
user281377

Trong ví dụ cụ thể của bạn ở trên, một ngoại lệ được đưa ra bởi vì phương thức không biết liệu nó sẽ được gọi với mã hóa được hỗ trợ hay không được hỗ trợ. Một cách xoay quanh vấn đề này sẽ là nếu có một nhà xây dựng khác giả định bộ ký tự chuẩn được đưa ra, điều này sẽ không cần phải tuyên bố rằng một ngoại lệ sẽ bị ném.
jordan

Câu trả lời:


27

Thói quen của tôi là, chỉ để ở bên an toàn, đưa một assertkhối vào bắt. Ai đó có thể thay đổi nội dung của trykhối sau và bạn có muốn biết nếu mã không thành công không?


Ý tưởng tốt; một đơn giản assert false;không thêm quá nhiều lộn xộn và làm rõ rằng tôi cho rằng khối bắt sẽ không bao giờ được nhập.
user281377

5
@ammoQ hoặc thậm chí bạn có thể thêm một tin nhắn để làm cho ý định của bạn hoàn toàn rõ ràng : assert false : "should never happen".
Péter Török

13
Thậm chí tốt hơn, "Không bao giờ nên xảy ra vì Java yêu cầu bộ ký tự ISO-8859-1 được hỗ trợ."
dan04

3
assertngụ ý khẳng định được kích hoạt. Tôi ném một cái UnexpectedException(cũng có lợi ích cho phép tôi có dấu vết ngăn xếp ...).
Chém

35

Nếu tôi đã được tặng một xu cho mỗi lần tôi thấy một bản ghi / lỗi, "Điều này sẽ không bao giờ xảy ra", tôi sẽ có ... tốt, hai xu. Nhưng vẫn...

Các khối bắt trống làm cho con nhện của tôi cảm thấy râm ran và hầu hết các công cụ phân tích mã tốt đều phàn nàn. Tôi sẽ tránh bằng mọi giá để trống chúng. Chắc chắn, bây giờ bạn biết lỗi không bao giờ có thể xảy ra, nhưng một năm sau, một người nào đó thực hiện tìm kiếm thay thế toàn cầu "ISO-8859-1" và đột nhiên bạn có thể gặp lỗi cực kỳ khó tìm.

Các assert falsegợi ý là tốt, nhưng kể từ khi khẳng định có thể bị vô hiệu hóa khi chạy, họ không bảo lãnh. Tôi sẽ sử dụng RuntimeExceptionthay thế. Những người đó sẽ không bị bắt bằng cách gọi các lớp và nếu chúng xảy ra, bạn sẽ có dấu vết ngăn xếp để cung cấp thông tin đầy đủ.


28

Tôi đã luôn luôn làm nó như thế này:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

Có thể hơi dài dòng (Java là ...), nhưng ít nhất bạn sẽ gặp lỗi xác nhận khi điều không thể xảy ra.

Nếu việc triển khai Java bị hỏng, bạn sẽ muốn nhận được thông báo lỗi tốt nhất có thể, càng nhanh càng tốt, thay vì bỏ qua những điều không thể. Và ngay cả khi việc triển khai Java không bị hỏng, ai đó có thể đã thay đổi mã của bạn thành "UTF8"(rất tiếc - có nên như "UTF-8"vậy không?).

Điều này nên là một ngoại lệ thời gian chạy ở nơi đầu tiên. JDK có đầy đủ các loại lựa chọn sai.


4
Sự phân rã xấu thực sự (hoặc thiếu sót nếu bạn muốn) là không có trường hợp Bộ ký tự được xác định trước cho 6 bộ ký tự mà Java yêu cầu. foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);- bây giờ sẽ không đẹp hơn và tránh bất kỳ sai lầm nào một lần và mãi mãi?
user281377

3
Thư viện ổi có hàng tấn những thứ này. Làm cho cuộc sống dễ dàng hơn.

3
Java 1.7+ không có các bộ ký tự được định nghĩa: docs.oracle.com/javase/7/docs/api/java/nio/charset/ . Sử dụng chúng như vậy: StandardCharsets.UTF_8.displayName ()
Michael

4

Nếu bạn là nhà phát triển duy nhất từng thấy mã này thì tôi sẽ nói nó ổn, nhưng nếu bạn không thì tôi sẽ coi đó là một khả năng thực sự hoặc ít nhất là thay đổi nhận xét "sẽ không bao giờ xảy ra" một cái gì đó hữu ích hơn


4

Một phần của những ngoại lệ này làm tôi khó chịu nhất là nó làm tổn thương phạm vi bảo hiểm mã của tôi.

Khi tôi bị ép buộc về phạm vi bảo hiểm, tôi sẽ đưa ra thử / bắt rằng "không bao giờ có thể xảy ra" (... hoặc chỉ khi tôi đang sử dụng một JVM đột biến mà bằng cách nào đó đã quên đưa "US-ASCII" vào) một lớp và phương thức đóng gói thử / bắt và thay thế ngoại lệ được kiểm tra theo một trong những cách được đề cập ở đây (thường ném một ngoại lệ không được kiểm tra bằng thông báo snide).

Sau đó, phạm vi bảo hiểm mã của tôi bị ảnh hưởng trong lớp tiện ích, nhưng không phải trong tất cả các tham chiếu đến hoạt động đó nằm rải rác xung quanh mã của tôi.

Đôi khi tôi sẽ dành thời gian để triển khai như các hoạt động trong một lớp học thực sự có ngữ nghĩa mạch lạc. Nhưng vì nó khá rõ ràng với các đồng đội của tôi những gì đang diễn ra, tôi thường chỉ đơn giản như tôi có thể & không phải lo lắng quá nhiều về thiết kế tốt nhất có thể.

Tuy nhiên, như một bình luận đã đề cập, Guava và các thư viện khác có cách để giảm bớt nỗi đau này - nhưng về cơ bản đó là cùng một chiến lược. Di chuyển sự khó chịu ra khỏi giai đoạn để mã chính của bạn không bị ảnh hưởng trong phạm vi bảo hiểm.

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.