Khi nào cần bắt java.lang.Error?


Câu trả lời:


101

Nói chung, không bao giờ.

Tuy nhiên, đôi khi bạn cần phải bắt lỗi cụ thể.

Nếu bạn đang viết mã khung-ish (tải các lớp của bên thứ 3), có thể nên nắm bắt LinkageError(không tìm thấy lớp def, liên kết không thỏa mãn, thay đổi lớp không tương thích).

Tôi cũng đã thấy một số mã lớp thứ ba ngu ngốc ném các lớp con Error, vì vậy bạn cũng sẽ phải xử lý chúng.

Nhân tiện, tôi không chắc là không thể phục hồi OutOfMemoryError.


3
Rằng tôi phải thực hiện chính xác để tải DLL, điều đó sẽ thất bại nếu chúng không được cấu hình đúng. Không phải là một lỗi nghiêm trọng trong trường hợp của ứng dụng này.
Mario Ortegón

7
Đôi khi có ý nghĩa để bắt OutOfMemoryError - ví dụ khi bạn đang tạo danh sách mảng lớn.
SpaceTrucker

3
@SpaceTrucker: cách tiếp cận đó có hoạt động tốt trong các ứng dụng đa luồng không, hoặc có rủi ro đáng kể khi phân bổ nhỏ hơn trong các luồng khác không thành công vì nó không? Có lẽ chỉ có thể nếu mảng của bạn chỉ đủ nhỏ để được phân bổ, nhưng không để lại gì cho bất kỳ ai khác.
PJTraill

@PJTraill Tôi không chắc về điều đó. Điều này sẽ yêu cầu một số mẫu thống kê thế giới thực. Tôi nghĩ rằng tôi đã thấy mã như vậy, nhưng không thể nhớ nó ở đâu.
SpaceTrucker

51

Không bao giờ. Bạn không bao giờ có thể chắc chắn rằng ứng dụng có thể thực thi dòng mã tiếp theo. Nếu bạn nhận được một OutOfMemoryError, bạn không có gì đảm bảo rằng bạn sẽ có thể làm bất cứ điều gì đáng tin cậy . Bắt RuntimeException và kiểm tra Ngoại lệ, nhưng không bao giờ Lỗi.

http://pmd.sourceforge.net/rules/strictexception.html


27
Không bao giờ nói không bao giờ. chúng tôi có mã kiểm tra thực hiện "khẳng định sai;" sau đó bắt Ass AssError để đảm bảo rằng cờ -ea được đặt. Khác với điều đó ... ừ, có lẽ không bao giờ ;-)
Lập trình viên ngoài vòng pháp luật

3
Làm thế nào về một ứng dụng máy chủ mà yêu cầu xử lý các luồng công nhân. Có thể không có ý nghĩa khi bắt throwable trên luồng công nhân để bẫy bất kỳ lỗi nào, và ít nhất là thử và ghi lại những gì đã sai?
Leigh

11
Không bao giờ ... ngoại trừ khi bạn thực sự cần. Không bao giờ là một từ mạnh mẽ và luôn có ngoại lệ cho các quy tắc. Nếu bạn đang xây dựng một khung công tác, không có khả năng là bạn sẽ phải nắm bắt và xử lý một số lỗi nhất định, ngay cả khi đó chỉ là để đăng nhập.
Robin

Làm thế nào về các lỗi, ví dụ NoSuchMethodError đến từ các phương thức thư viện của bên thứ ba?
ha9u63ar

@OutlawProgrammer Chỉ để ghi lại, có nhiều cách khác để thực hiện bài kiểm tra tương tự:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel

16

Nói chung bạn nên luôn luôn bắt java.lang.Error và ghi nó vào một bản ghi hoặc hiển thị nó cho người dùng. Tôi làm việc trong bộ phận hỗ trợ và thấy hàng ngày rằng các lập trình viên không thể biết chuyện gì đã xảy ra trong một chương trình.

Nếu bạn có một chủ đề daemon thì bạn phải ngăn chặn nó bị chấm dứt. Trong các trường hợp khác, ứng dụng của bạn sẽ hoạt động chính xác.

Bạn chỉ nên bắt java.lang.Errorở mức cao nhất.

Nếu bạn nhìn vào danh sách các lỗi bạn sẽ thấy rằng hầu hết có thể được xử lý. Ví dụ: ZipErrorxảy ra khi đọc các tệp zip bị hỏng.

Các lỗi phổ biến nhất là OutOfMemoryErrorNoClassDefFoundError, cả hai trong hầu hết các trường hợp vấn đề thời gian chạy.

Ví dụ:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

có thể tạo ra OutOfMemoryErrornhưng đó là một vấn đề thời gian chạy và không có lý do gì để chấm dứt chương trình của bạn.

NoClassDefFoundErrorxảy ra hầu hết nếu không có thư viện hoặc nếu bạn làm việc với phiên bản Java khác. Nếu nó là một phần tùy chọn trong chương trình của bạn thì bạn không nên chấm dứt chương trình của mình.

Tôi có thể đưa ra nhiều ví dụ nữa về lý do tại sao nên nắm bắt Throwableở cấp cao nhất và tạo ra một thông báo lỗi hữu ích.


Tôi nghi ngờ sẽ tốt hơn trong những trường hợp đó khi thất bại với daemon với những cảnh báo thích hợp sau đó có khả năng nó vẫn tồn tại như một con ma etherial trên một jvm thất bại, nơi nó có thể đưa ra lý do sai lầm rằng nó thực sự còn sống và đang làm gì đó
Andrew Norman

OutOfMemoryErrorkhông phải là lỗi thời gian chạy, không có gì đảm bảo rằng ứng dụng có thể phục hồi từ nó. Nếu bạn may mắn, bạn có thể nhận được OOM new byte[largeNumber]nhưng nếu phân bổ đó không đủ để gây ra OOM, nó có thể được kích hoạt trong dòng tiếp theo hoặc chuỗi tiếp theo. Đây là vấn đề thời gian chạy vì nếu lengthđầu vào không đáng tin cậy thì nó phải được xác nhận trước khi gọi new byte[].
Jeeyoung Kim

NoClassDefFoundErrorcó thể xảy ra ở bất cứ đâu , vì nó được gọi khi mã java được biên dịch không thể tìm thấy một lớp. Nếu JDK của bạn bị định cấu hình sai, nó có thể kích hoạt việc cố gắng sử dụng java.util.*lớp và thực tế không thể lập trình chống lại nó. Nếu bạn tùy chọn bao gồm một phụ thuộc, bạn nên sử dụng ClassLoaderđể kiểm tra xem nó có tồn tại hay không ClassNotFoundException.
Jeeyoung Kim

1
ZipErrorchỉ ra rằng tệp jar chứa các lớp là một tệp zip bị hỏng. Đây là một vấn đề khá nghiêm trọng và tại thời điểm này, bạn không thể tin tưởng bất kỳ mã nào được thực thi và đó là điều vô trách nhiệm khi cố gắng "phục hồi" từ nó.
Jeeyoung Kim

2
Nói chung, có thể hữu ích để bắt java.lang.Errorhoặc java.lang.Throwableở cấp cao nhất và cố gắng làm điều gì đó với nó - nói rằng đăng nhập một thông báo lỗi. Nhưng tại thời điểm đó, không có gì đảm bảo rằng điều này sẽ được thực thi. Nếu JVM của bạn là OOMing, cố gắng đăng nhập có thể phân bổ nhiều Strings hơn để kích hoạt một OOM khác.
Jeeyoung Kim

15

Trong môi trường đa luồng, bạn thường muốn bắt nó nhất! Khi bạn bắt được nó, đăng nhập nó và chấm dứt toàn bộ ứng dụng! Nếu bạn không làm điều đó, một số chủ đề có thể đang thực hiện một phần quan trọng sẽ bị chết và phần còn lại của ứng dụng sẽ nghĩ rằng mọi thứ đều bình thường. Trong số đó, nhiều tình huống không mong muốn có thể xảy ra. Một vấn đề nhỏ nhất là bạn sẽ không thể dễ dàng tìm ra gốc rễ của vấn đề, nếu các luồng khác bắt đầu đưa ra một số ngoại lệ vì một luồng không hoạt động.

Ví dụ: vòng lặp thường là:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

Ngay cả trong một số trường hợp, bạn sẽ muốn xử lý các Lỗi khác nhau, ví dụ, trên OutOfMemoryError, bạn có thể đóng ứng dụng thường xuyên (thậm chí có thể giải phóng một số bộ nhớ và tiếp tục), đối với một số người khác, bạn không thể làm gì nhiều.


1
Bắt OutOfMemoryError và tiếp tục thay vì hiện tại kịp thời là không khôn ngoan vì chương trình của bạn sau đó ở trạng thái không xác định .
Raedwald

1
hệ thống gọi điện, thoát khỏi việc bắt một ném có thể dẫn đến hậu quả không lường trước là giết tất cả mọi thứ đang chạy trên JVM và không chỉ ứng dụng đang được đề cập đến. Thông thường không phải là một cách thực hành tốt cho các ứng dụng web có thể được lưu trữ trên máy chủ ứng dụng với các ứng dụng web khác (chưa kể nó sẽ ảnh hưởng đến chính máy chủ ứng dụng).
Andrew Norman

9

Rất hiếm.

Tôi chỉ nói ở cấp cao nhất của một chủ đề để ATTEMPT phát hành một thông báo với lý do cho một chủ đề bị chết.

Nếu bạn đang ở trong một khung làm việc này cho bạn, hãy để nó vào khung.


6

Hầu như không bao giờ. Lỗi được thiết kế để trở thành vấn đề mà các ứng dụng thường không thể làm gì được. Ngoại lệ duy nhất có thể là xử lý việc trình bày lỗi nhưng ngay cả điều đó có thể không diễn ra theo kế hoạch tùy thuộc vào lỗi.


6

Một Errorthường không nên bị bắt , vì nó chỉ ra một tình trạng bất thường không bao giờ nên xảy ra .

Từ Đặc tả API Java cho Errorlớp:

An Errorlà một lớp con Throwable chỉ ra những vấn đề nghiêm trọng mà một ứng dụng hợp lý không nên cố gắng nắm bắt. Hầu hết các lỗi như vậy là điều kiện bất thường. [...]

Một phương thức không bắt buộc phải khai báo trong mệnh đề ném của nó bất kỳ lớp con Lỗi nào có thể bị ném trong quá trình thực thi phương thức nhưng không bị bắt, vì các lỗi này là điều kiện bất thường không bao giờ xảy ra.

Như đặc tả đề cập, một Errorchỉ được ném trong các trường hợp là Cơ hội, khi Errorxảy ra, có rất ít ứng dụng có thể làm được và trong một số trường hợp, chính Máy ảo Java có thể ở trạng thái không ổn định (như VirtualMachineError)

Mặc dù an Errorlà một lớp con Throwablecó nghĩa là nó có thể bị bắt bởi một try-catchmệnh đề, nhưng có lẽ nó không thực sự cần thiết, vì ứng dụng sẽ ở trạng thái bất thường khi Errorbị JVM ném.

Cũng có một phần ngắn về chủ đề này trong Phần 11.5 Phân cấp ngoại lệ của Đặc tả ngôn ngữ Java, Phiên bản 2 .


6

Nếu bạn đủ điên rồ để tạo ra một khung thử nghiệm đơn vị mới, người chạy thử nghiệm của bạn có thể sẽ cần phải bắt java.lang.AssertsError bị ném bởi bất kỳ trường hợp thử nghiệm nào.

Nếu không, xem câu trả lời khác.


5

Và có một vài trường hợp khác nếu bạn gặp Lỗi, bạn phải điều chỉnh lại . Ví dụ ThreadDeath không bao giờ bị bắt, điều này có thể gây ra vấn đề lớn là bạn bắt nó trong một môi trường chứa (ví dụ: một máy chủ ứng dụng):

Một ứng dụng chỉ nên bắt các thể hiện của lớp này nếu nó phải dọn sạch sau khi bị chấm dứt không đồng bộ. Nếu ThreadDeath bị bắt bởi một phương thức, điều quan trọng là nó phải được lưu lại để luồng thực sự chết.


2
Đây thực sự không phải là vấn đề vì đơn giản là bạn không bắt được Errors.
Bombe

4

Rất, rất hiếm khi.

Tôi đã làm nó chỉ cho một trường hợp rất cụ thể được biết đến. Ví dụ: java.lang.UnsatisfiedLinkError có thể bị ném nếu hai ClassLoader độc lập tải cùng một DLL. (Tôi đồng ý rằng tôi nên chuyển JAR sang trình nạp lớp chung)

Nhưng trường hợp phổ biến nhất là bạn cần đăng nhập để biết điều gì đã xảy ra khi người dùng đến khiếu nại. Bạn muốn một tin nhắn hoặc một cửa sổ bật lên cho người dùng, sau đó âm thầm chết.

Ngay cả lập trình viên trong C / C ++, họ cũng gặp lỗi và thông báo điều gì đó mà mọi người không hiểu trước khi thoát (ví dụ như lỗi bộ nhớ).


3

Trong một ứng dụng Android, tôi bắt gặp java.lang.VerifyError . Một thư viện mà tôi đang sử dụng sẽ không hoạt động trong các thiết bị có phiên bản cũ của HĐH và mã thư viện sẽ gây ra lỗi như vậy. Tất nhiên tôi có thể tránh lỗi bằng cách kiểm tra phiên bản HĐH khi chạy, nhưng:

  • SDK được hỗ trợ cũ nhất có thể thay đổi trong tương lai cho thư viện cụ thể
  • Khối lỗi thử bắt là một phần của cơ chế giảm trở lại lớn hơn. Một số thiết bị cụ thể, mặc dù chúng được cho là hỗ trợ thư viện, ném ngoại lệ. Tôi bắt ConfirmError và tất cả các trường hợp ngoại lệ để sử dụng giải pháp dự phòng.

3

khá thuận tiện để bắt java.lang.AssertsError trong môi trường thử nghiệm ...


Giá trị nào bạn đang cố gắng thêm?
lpapp

thêm giá trị của bộ kiểm tra không hủy bỏ
Jono

2

Tốt nhất chúng ta không nên xử lý / bắt lỗi. Nhưng có thể có những trường hợp chúng ta cần phải làm, dựa trên yêu cầu của khung hoặc ứng dụng. Giả sử tôi có một trình nền XML Parser thực hiện DOM Parser tiêu tốn nhiều Bộ nhớ hơn. Nếu có một yêu cầu như luồng Parser thì không nên chết khi nhận được OutOfMemoryError , thay vào đó, nó sẽ xử lý nó và gửi tin nhắn / mail cho quản trị viên của ứng dụng / khung.


1

lý tưởng là chúng ta không bao giờ nên bắt Lỗi trong ứng dụng Java của mình vì đây là một điều kiện bất thường. Ứng dụng sẽ ở trạng thái bất thường và có thể dẫn đến tình trạng say xe hoặc đưa ra một số kết quả sai nghiêm trọng.


1

Có thể thích hợp để bắt lỗi trong các bài kiểm tra đơn vị kiểm tra xác nhận được thực hiện. Nếu ai đó vô hiệu hóa các xác nhận hoặc xóa các xác nhận mà bạn muốn biết


1

Có một lỗi khi JVM không hoạt động như mong đợi hoặc đang trên bờ vực. Nếu bạn bắt lỗi, không có gì đảm bảo rằng khối bắt sẽ chạy, và thậm chí ít hơn là nó sẽ chạy cho đến hết.

Nó cũng sẽ phụ thuộc vào máy tính đang chạy, trạng thái bộ nhớ hiện tại, vì vậy không có cách nào để kiểm tra, thử và làm hết sức mình. Bạn sẽ chỉ có một kết quả xấu.

Bạn cũng sẽ hạ cấp khả năng đọc mã của bạn.

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.