Hiểu các ngoại lệ được kiểm tra và không được kiểm tra trong Java


703

Joshua Bloch trong " Java hiệu quả " đã nói rằng

Sử dụng các ngoại lệ được kiểm tra cho các điều kiện có thể phục hồi và ngoại lệ thời gian chạy cho các lỗi lập trình (Mục 58 trong phiên bản 2)

Hãy xem tôi hiểu điều này có đúng không.

Dưới đây là sự hiểu biết của tôi về một ngoại lệ được kiểm tra:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Ở trên có được coi là một ngoại lệ được kiểm tra không?

2. RuntimeException có phải là ngoại lệ không được kiểm tra không?

Dưới đây là sự hiểu biết của tôi về một ngoại lệ không được kiểm soát:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Bây giờ, không phải mã trên cũng là một ngoại lệ được kiểm tra? Tôi có thể cố gắng phục hồi tình hình như thế này? Tôi có thể? (Lưu ý: câu hỏi thứ 3 của tôi nằm trong phần catchtrên)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Tại sao mọi người làm điều này?

public void someMethod throws Exception{

}

Tại sao họ để bong bóng ngoại lệ lên? Không xử lý lỗi sớm hơn tốt hơn? Tại sao bong bóng lên?

6. Tôi có nên tạo ra ngoại lệ chính xác hoặc che giấu nó bằng Exception không?

Dưới đây là bài đọc của tôi

Trong Java, khi nào tôi nên tạo một ngoại lệ được kiểm tra và khi nào nên là ngoại lệ thời gian chạy?

Khi nào nên chọn ngoại lệ được kiểm tra và không được kiểm tra


6
Tôi có một ví dụ tuyệt vời về một ngoại lệ không được kiểm soát. Tôi có một DataSerieslớp chứa dữ liệu luôn phải theo thứ tự dựa trên thời gian. Có một phương pháp để thêm một cái mới DataPointvào cuối a DataSeries. Nếu tất cả các mã của tôi hoạt động chính xác trong suốt dự án, DataPointkhông bao giờ nên thêm mã vào cuối có ngày trước với mã đã kết thúc. Mỗi mô-đun trong toàn bộ dự án được xây dựng với sự thật này. Tuy nhiên, tôi kiểm tra điều kiện này và ném một ngoại lệ không được kiểm tra nếu nó xảy ra. Tại sao? Nếu nó xảy ra, tôi muốn biết ai đang làm điều này và sửa nó.
Erick Robertson

3
Để thêm sự nhầm lẫn hơn nữa. Nhiều người đã ủng hộ các trường hợp ngoại lệ được kiểm tra ~ 10 năm trước, nhưng quan điểm ngày nay ngày càng hướng tới "các ngoại lệ được kiểm tra là xấu". (Tuy nhiên tôi không đồng ý về điều đó)
Kaj

10
Nó chỉ hữu ích để xử lý Ngoại lệ khi bạn có việc cần làm với nó, nếu không, bạn nên để người gọi xử lý. Ghi nhật ký và giả vờ không xảy ra thường không hữu ích. Chỉ cần ném lại nó là vô nghĩa. Gói trong RuntimeException không hữu ích như một số người nghĩ, nó chỉ khiến trình biên dịch ngừng giúp bạn. (IMHO)
Peter Lawrey

40
Chúng ta nên ngừng sử dụng các thuật ngữ gây hiểu lầm toàn diện về các ngoại lệ được kiểm tra / không được kiểm tra . Chúng nên được gọi là ngoại lệ kiểm tra bắt buộc so với kiểm tra không bắt buộc .
Phúc cho Geek

3
Tôi cũng đã nghĩ abt ur 5 điểm công khai void phương thức_name ném Ngoại lệ {} tại sao một số người làm điều đó?
Maveň ツ

Câu trả lời:


474

Nhiều người nói rằng các trường hợp ngoại lệ được kiểm tra (tức là những trường hợp mà bạn nên nắm bắt hoặc suy nghĩ lại rõ ràng) hoàn toàn không nên được sử dụng. Ví dụ, chúng đã bị loại trong C # và hầu hết các ngôn ngữ không có chúng. Vì vậy, bạn luôn có thể ném một lớp con của RuntimeException(ngoại lệ không được kiểm tra)

Tuy nhiên, tôi nghĩ rằng các ngoại lệ được kiểm tra là hữu ích - chúng được sử dụng khi bạn muốn buộc người dùng API của bạn nghĩ cách xử lý tình huống đặc biệt (nếu có thể phục hồi được). Chỉ là các ngoại lệ được kiểm tra được sử dụng quá mức trong nền tảng Java, khiến mọi người ghét chúng.

Đây là quan điểm mở rộng của tôi về chủ đề này .

Đối với các câu hỏi cụ thể:

  1. NumberFormatExceptionxem xét một ngoại lệ được kiểm tra?
    Số NumberFormatExceptionkhông được chọn (= là lớp con của RuntimeException). Tại sao? Tôi không biết. (nhưng nên có một phương pháp isValidInteger(..))

  2. RuntimeExceptionmột ngoại lệ không được kiểm soát?
    Đúng chính xác.

  3. Tôi nên làm gì ở đây?
    Nó phụ thuộc vào vị trí của mã này và những gì bạn muốn xảy ra. Nếu nó ở trong lớp UI - hãy bắt nó và hiển thị cảnh báo; nếu nó ở trong lớp dịch vụ - đừng bắt nó - hãy để nó bong bóng. Đừng nuốt ngoại lệ. Nếu một ngoại lệ xảy ra trong hầu hết các trường hợp, bạn nên chọn một trong những trường hợp sau:

    • đăng nhập và trở lại
    • nghĩ lại nó (khai báo nó sẽ được ném theo phương thức)
    • xây dựng một ngoại lệ mới bằng cách chuyển cái hiện tại trong hàm tạo
  4. Bây giờ, không phải mã trên cũng là một ngoại lệ được kiểm tra? Tôi có thể cố gắng phục hồi tình hình như thế này? Tôi có thể?
    Nó đã có thể được. Nhưng không có gì ngăn bạn bắt ngoại lệ không được kiểm tra

  5. Tại sao mọi người thêm lớp Exceptiontrong mệnh đề ném?
    Hầu hết thường bởi vì mọi người lười biếng để xem xét những gì để bắt và những gì để suy nghĩ lại. Ném Exceptionlà một thực hành xấu và nên tránh.

Than ôi, không có quy tắc duy nhất để cho phép bạn xác định khi nào nên bắt, khi nào nên suy nghĩ lại, khi nào nên sử dụng kiểm tra và khi nào sử dụng ngoại lệ không được kiểm tra. Tôi đồng ý điều này gây ra nhiều nhầm lẫn và rất nhiều mã xấu. Nguyên tắc chung được nêu bởi Bloch (bạn đã trích dẫn một phần của nó). Và nguyên tắc chung là lấy lại một ngoại lệ cho lớp nơi bạn có thể xử lý nó.


36
Về việc ném Ngoại lệ, không phải lúc nào mọi người cũng lười biếng, điều phổ biến là bạn, khi bạn triển khai các khung, hãy để người dùng của khung có thể ném bất kỳ ngoại lệ nào. Ví dụ, bạn có thể kiểm tra chữ ký của giao diện Có thể gọi trong JSE
Kaj

10
@Kaj - vâng, những thứ chung chung như Callable, đánh chặn và thích là những trường hợp đặc biệt. Nhưng trong hầu hết các trường hợp, đó là vì mọi người lười biếng :)
Bozho

7
re: 3.1 "đăng nhập và trả lại" Làm như vậy một cách thận trọng. Điều này rất gần với ăn hoặc trốn và ngoại lệ. Tôi sẽ làm điều này cho một cái gì đó không chỉ ra vấn đề, điều đó không thực sự đặc biệt. Nhật ký bị ngập và bỏ qua quá dễ dàng.
Chris

4
"Khi bạn muốn buộc người dùng API của bạn nghĩ cách xử lý tình huống đặc biệt" - bạn không thể buộc bất cứ ai phải suy nghĩ nếu họ không muốn. Nếu họ không muốn nghĩ, họ sẽ viết một khối ngoại lệ kém mà không làm gì cả, hoặc tệ hơn, xóa hoặc can thiệp vào thông tin lỗi nghiêm trọng. Đó là lý do tại sao các trường hợp ngoại lệ được kiểm tra là một thất bại.
adrianos

3
@adrianos "... bạn không thể ép buộc bất cứ ai nghĩ nếu họ không muốn ...." Với dòng suy nghĩ này, chúng tôi cũng có thể loại bỏ các lỗi biên dịch .... Tôi không thực sự nhắm mục tiêu cho bạn, tôi đã nghe thấy điều này lập luận hết lần này đến lần khác và vẫn thấy đó là lời giải thích kém nhất có thể cho việc dán nhãn Ngoại lệ được kiểm tra là một thất bại. Như một lưu ý phụ, tôi đã thấy trước một ngôn ngữ như vậy trong đó việc biên dịch (và cả lỗi thời gian chạy thực sự) thực sự không thể thực hiện được bằng cách bỏ qua. Con đường đó dẫn đến một số nơi rất tối.
Newtopian

233

Cho dù một cái gì đó là "ngoại lệ được kiểm tra" không liên quan gì đến việc bạn có bắt được nó hay bạn làm gì trong khối bắt. Đó là một tài sản của các lớp ngoại lệ. Bất cứ điều gì đó là một lớp con của Exception trừ cho RuntimeExceptionvà lớp con của nó là một ngoại lệ kiểm tra.

Trình biên dịch Java buộc bạn phải bắt các ngoại lệ được kiểm tra hoặc khai báo chúng trong chữ ký phương thức. Nó được cho là để cải thiện sự an toàn của chương trình, nhưng ý kiến ​​của đa số dường như là nó không xứng đáng với các vấn đề thiết kế mà nó tạo ra.

Tại sao họ để bong bóng ngoại lệ lên? Không xử lý lỗi càng sớm càng tốt? Tại sao bong bóng lên?

Bởi vì đó là toàn bộ điểm ngoại lệ. Nếu không có khả năng này, bạn sẽ không cần ngoại lệ. Chúng cho phép bạn xử lý các lỗi ở cấp độ bạn chọn, thay vì buộc bạn phải xử lý chúng theo các phương pháp cấp thấp nơi chúng xảy ra ban đầu.


3
Cảm ơn bạn! Thỉnh thoảng tôi ném ngoại lệ ra khỏi phương pháp của mình vì nguyên tắc tào lao trong crape. Tôi là một trong những nhà phát triển trong nhóm của tôi muốn nhập một biểu thức xpath không hợp lệ tùy thuộc vào họ để xử lý ngoại lệ. Trong trường hợp không thể xảy ra, họ bắt gặp một ngoại lệ và không làm gì họ sẽ nghe về nó trong đánh giá mã.
jeremyjjbrown

12
"Bất cứ thứ gì là một lớp con của throwable ngoại trừ RuntimeException và các lớp con của nó là một ngoại lệ được kiểm tra." - Tuyên bố của bạn không chính xác. Lỗi cũng kế thừa throwable và nó không được kiểm tra.
Bartzilla

8
@JonasE Rich: về cơ bản, một ưu điểm chính của các trường hợp ngoại lệ là chúng cho phép bạn chọn vị trí trong ngăn xếp cuộc gọi mà bạn muốn xử lý lỗi, thường khá cao, trong khi vẫn giữ các lớp ở giữa hoàn toàn không có các thành phần xử lý lỗi. Đã kiểm tra ngoại lệ phá hủy chính xác lợi thế đó. Một vấn đề khác là sự phân biệt được kiểm tra / không được kiểm tra được gắn với lớp ngoại lệ, cũng đại diện cho một phân loại khái niệm về các ngoại lệ - trộn lẫn hai khía cạnh không nhất thiết phải liên quan.
Michael Borgwardt

2
"nhưng ý kiến ​​của đa số dường như là nó không xứng đáng với các vấn đề thiết kế mà nó tạo ra." - Xin trích dẫn?
kervin

3
@Bartzilla Vâng. Để cho đầy đủ, như javadoc đã Throwablenói: "Có thể ném được và bất kỳ lớp con nào của throwable không phải là lớp con của RuntimeException hoặc Error đều được coi là ngoại lệ được kiểm tra"
Bart van Heukelom

74
  1. Là ở trên được coi là một ngoại lệ được kiểm tra? Không Thực tế là bạn đang xử lý một ngoại lệ không biến nó thành một Checked Exceptionnếu nó là một RuntimeException.

  2. RuntimeExceptionmột unchecked exception? Đúng

Checked Exceptionssubclassescủa java.lang.Exception Unchecked Exceptionssubclassescủajava.lang.RuntimeException

Các cuộc gọi ném ngoại lệ được kiểm tra cần phải được đặt trong một khối {} thử hoặc được xử lý ở mức trên trong trình gọi của phương thức. Trong trường hợp đó, phương thức hiện tại phải khai báo rằng nó ném các ngoại lệ đã nói để người gọi có thể sắp xếp phù hợp để xử lý ngoại lệ.

Hi vọng điêu nay co ich.

H: Tôi có nên tạo ra ngoại lệ chính xác hoặc che giấu nó bằng Exception không?

A: Vâng, đây là một câu hỏi rất hay và xem xét thiết kế quan trọng. Lớp Ngoại lệ là một lớp ngoại lệ rất chung và có thể được sử dụng để bọc các ngoại lệ cấp thấp bên trong. Bạn nên tạo một ngoại lệ tùy chỉnh và bọc bên trong nó. Nhưng, và một vấn đề lớn - Không bao giờ che khuất nguyên nhân gốc rễ tiềm ẩn. Đối với người cũ, Don't everhãy làm theo -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Thay vào đó hãy làm như sau:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Ăn mất nguyên nhân gốc ban đầu chôn vùi nguyên nhân thực sự ngoài phục hồi là một cơn ác mộng đối với các nhóm hỗ trợ sản xuất trong đó tất cả những gì họ được cấp quyền truy cập là nhật ký ứng dụng và thông báo lỗi. Mặc dù sau này là một thiết kế tốt hơn nhưng nhiều người không sử dụng nó thường xuyên vì các nhà phát triển không chuyển được thông điệp cơ bản đến người gọi. Vì vậy, hãy ghi chú Always pass on the actual exceptionlại : quay lại xem có bao bọc trong bất kỳ ngoại lệ cụ thể nào của ứng dụng hay không.

Đang thử RuntimeExceptions

RuntimeExceptions như một quy tắc chung không nên bị bắt. Chúng thường báo hiệu một lỗi lập trình và nên để yên. Thay vào đó, lập trình viên nên kiểm tra tình trạng lỗi trước khi gọi một số mã có thể dẫn đến a RuntimeException. Ví dụ:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Đây là một thực hành lập trình xấu. Thay vào đó, kiểm tra null nên được thực hiện như -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Nhưng đôi khi việc kiểm tra lỗi như vậy rất tốn kém như định dạng số, hãy xem xét điều này -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Ở đây, việc kiểm tra lỗi trước khi gọi không đáng để thực hiện vì về cơ bản nó có nghĩa là sao chép tất cả mã chuyển đổi chuỗi thành số nguyên bên trong phương thức parseInt () - và dễ bị lỗi nếu được nhà phát triển triển khai. Vì vậy, tốt hơn là chỉ cần làm đi với thử bắt.

Vì vậy, NullPointerExceptionNumberFormatExceptioncả hai RuntimeExceptions, việc bắt một NullPointerExceptionnên được thay thế bằng kiểm tra null duyên dáng trong khi tôi khuyên bạn nên nắm bắt một NumberFormatExceptioncách rõ ràng để tránh có thể giới thiệu mã dễ bị lỗi.


Cảm ơn bạn. Một câu hỏi nữa khi bạn sủi bọt lên exception, tôi nên tạo ra ngoại lệ chính xác hoặc che giấu nó bằng cách sử dụng Exception. Tôi viết mã lên trên một số mã kế thừa, và Exceptionbị nổi lên khắp nơi. Tôi tự hỏi nếu đây là hành vi chính xác?
Thắng Phạm

1
Đây là một câu hỏi rất hay và quan trọng, đã chỉnh sửa câu trả lời của tôi để bao gồm phần giải thích.
d-sống

Cảm ơn rât nhiều. Bạn có thể chỉ cho tôi nội dung LoginFailureException(sqle)không?
Thắng Phạm

1
Tôi không có bất kỳ mã nào cho những thứ đó, tôi chỉ nấu các tên, v.v. Nếu bạn thấy java.lang.Exception, nó có 4 hàm tạo hai trong số chúng chấp nhận java.lang.Throwable. Trong đoạn trích ở trên, tôi giả sử LoginFailureExceptionmở rộng Exceptionvà tuyên bố một nhà xây dựngpublic LoginFailureException(Throwable cause) { super(cause) }
d-live

Câu trả lời tốt nhất về chủ đề. Tôi nghĩ không nên bắt ngoại lệ thời gian chạy vì những ngoại lệ này xảy ra do thiếu lập trình tốt. Tôi hoàn toàn đồng ý với phần "Ăn mất nguyên nhân gốc rễ chôn vùi nguyên nhân thực sự ngoài phục hồi là một cơn ác mộng đối với các nhóm hỗ trợ sản xuất, nơi tất cả những gì họ được cấp quyền truy cập là nhật ký ứng dụng và thông báo lỗi."
huseyin

19

1. Nếu bạn không chắc chắn về một ngoại lệ, hãy kiểm tra API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Vâng, và mọi ngoại lệ mở rộng nó.

3. Không cần phải bắt và ném ngoại lệ tương tự. Bạn có thể hiển thị Hộp thoại Tệp mới trong trường hợp này.

4 . FileNotFoundException đã là một ngoại lệ kiểm tra.

5. Nếu dự kiến ​​rằng phương thức gọi someMethodđể bắt ngoại lệ, thì phương thức sau có thể được ném ra. Nó chỉ "chuyền bóng". Một ví dụ về việc sử dụng nó sẽ là nếu bạn muốn ném nó vào các phương thức riêng tư của riêng bạn và thay vào đó xử lý ngoại lệ trong phương thức công khai của bạn.

Một cách đọc tốt là chính tài liệu của Oracle: http://doad.oracle.com/javase/tutorial/essential/exceptions/r nb.html

Tại sao các nhà thiết kế quyết định buộc một phương thức chỉ định tất cả các ngoại lệ được kiểm tra chưa được kiểm tra có thể được ném trong phạm vi của nó? Bất kỳ ngoại lệ nào có thể được ném bởi một phương thức là một phần của giao diện lập trình công khai của phương thức. Những người gọi một phương thức phải biết về các ngoại lệ mà một phương thức có thể đưa ra để họ có thể quyết định những gì cần làm về chúng. Các ngoại lệ này là một phần của giao diện lập trình của phương thức đó như các tham số và giá trị trả về của nó.

Câu hỏi tiếp theo có thể là: "Nếu thật tốt khi ghi lại API của phương thức, bao gồm các ngoại lệ mà nó có thể đưa ra, tại sao không chỉ định ngoại lệ thời gian chạy quá?" Các ngoại lệ thời gian chạy thể hiện các vấn đề là kết quả của một vấn đề lập trình và do đó, mã máy khách API có thể được mong đợi một cách hợp lý để phục hồi từ chúng hoặc xử lý chúng theo bất kỳ cách nào. Những vấn đề như vậy bao gồm các ngoại lệ số học, chẳng hạn như chia cho số 0; ngoại lệ con trỏ, chẳng hạn như cố gắng truy cập một đối tượng thông qua tham chiếu null; và ngoại lệ lập chỉ mục, chẳng hạn như cố gắng truy cập một phần tử mảng thông qua một chỉ mục quá lớn hoặc quá nhỏ.

Ngoài ra còn có một chút thông tin quan trọng trong Đặc tả ngôn ngữ Java :

Các lớp ngoại lệ được kiểm tra có tên trong mệnh đề ném là một phần của hợp đồng giữa người triển khai và người sử dụng phương thức hoặc hàm tạo .

Điểm mấu chốt IMHO là bạn có thể bắt được bất kỳ RuntimeException, nhưng bạn không bắt buộc và trên thực tế, việc triển khai không bắt buộc phải duy trì các ngoại lệ không được kiểm tra tương tự, vì chúng không phải là một phần của hợp đồng.


Cảm ơn bạn. Một câu hỏi nữa khi bạn sủi bọt lên exception, tôi nên tạo ra ngoại lệ chính xác hoặc che giấu nó bằng cách sử dụng Exception. Tôi viết mã lên trên một số mã kế thừa, và Exceptionbị nổi lên khắp nơi. Tôi tự hỏi nếu đây là hành vi chính xác?
Thắng Phạm

1
@Harry Tôi sẽ để những người có nhiều kiến ​​thức hơn tôi trả lời rằng: stackoverflow.com/questions
409563 / Uy

10

1) Không, NumberFormatException là Ngoại lệ không được kiểm tra. Mặc dù bạn đã bắt được nó (bạn không bắt buộc) vì nó không được kiểm tra. Điều này là bởi vì nó là một lớp con trong IllegalArgumentExceptionđó là một lớp con của RuntimeException.

2) RuntimeExceptionlà gốc của tất cả các Ngoại lệ không được kiểm tra. Mỗi lớp con của RuntimeExceptionkhông được kiểm tra. Tất cả các trường hợp ngoại lệ khác và Throwableđược kiểm tra ngoại trừ lỗi (đi kèm Throwable).

3/4) Bạn có thể cảnh báo người dùng rằng họ đã chọn một tệp không tồn tại và yêu cầu một tệp mới. Hoặc chỉ cần thoát thông báo cho người dùng rằng họ đã nhập một cái gì đó không hợp lệ.

5) Ném và bắt 'Exception'là thực hành xấu. Nhưng nói chung, bạn có thể đưa ra các ngoại lệ khác để người gọi có thể quyết định cách xử lý. Ví dụ: nếu bạn đã viết một thư viện để xử lý việc đọc một số đầu vào tệp và phương thức của bạn đã được thông qua một tệp không tồn tại, bạn không biết làm thế nào để xử lý việc đó. Người gọi có muốn hỏi lại hay bỏ cuộc không? Vì vậy, bạn ném Exception lên chuỗi trở lại cho người gọi.

Trong nhiều trường hợp, một sự cố unchecked Exceptionxảy ra do lập trình viên không xác minh đầu vào (trong trường hợp NumberFormatExceptiontrong câu hỏi đầu tiên của bạn). Đó là lý do tại sao không bắt được chúng, bởi vì có nhiều cách thanh lịch hơn để tránh tạo ra những ngoại lệ đó.


Cảm ơn bạn. Một câu hỏi nữa khi bạn sủi bọt lên exception, tôi nên tạo ra ngoại lệ chính xác hoặc che giấu nó bằng cách sử dụng Exception. Tôi viết mã lên trên một số mã kế thừa, và Exceptionbị nổi lên khắp nơi. Tôi tự hỏi nếu đây là hành vi chính xác?
Thắng Phạm

Bạn có thể chỉ cần phương pháp của bạn cũng ném Ngoại lệ (không lý tưởng). Hoặc bắt Exception và ném Exception tốt hơn (như IOException hoặc một cái gì đó). Tất cả các ngoại lệ có thể lấy Ngoại lệ trong hàm tạo của chúng làm 'nguyên nhân', vì vậy bạn nên sử dụng ngoại lệ đó.
dontocsata

8

Đã kiểm tra - Dễ xảy ra. Đã kiểm tra trong thời gian biên dịch.

Ví dụ: FileOperations

UnChecked - Do dữ liệu xấu. Đã kiểm tra trong thời gian chạy.

Ví dụ..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Ở đây ngoại lệ là do dữ liệu xấu và không có cách nào có thể xác định được trong thời gian biên dịch.


6

Các ngoại lệ được kiểm tra được kiểm tra tại thời điểm biên dịch bởi JVM và liên quan đến các tài nguyên (tệp / db / stream / socket, v.v.). Động cơ của ngoại lệ được kiểm tra là tại thời điểm biên dịch nếu tài nguyên không có sẵn, ứng dụng nên xác định một hành vi thay thế để xử lý việc này trong khối bắt / cuối cùng.

Các ngoại lệ không được kiểm tra là các lỗi lập trình đơn thuần, tính toán sai, dữ liệu null hoặc thậm chí các lỗi trong logic nghiệp vụ có thể dẫn đến các ngoại lệ về thời gian chạy. Nó hoàn toàn tốt để xử lý / bắt các ngoại lệ không được kiểm tra trong mã.

Giải thích được lấy từ http://coder2design.com/java-interview-questions/


5

Mô tả yêu thích tuyệt đối của tôi về sự khác biệt giữa các trường hợp ngoại lệ không được kiểm tra và được kiểm tra được cung cấp bởi bài viết theo dõi Hướng dẫn Java, " Ngoại lệ không được kiểm tra - Cuộc tranh cãi " (xin lỗi để có được tất cả các điều cơ bản trên bài đăng này - nhưng, hey, những điều cơ bản đôi khi là tốt nhất):

Đây là hướng dẫn quan trọng: Nếu một khách hàng có thể được mong đợi phục hồi một cách hợp lý từ một ngoại lệ, hãy biến nó thành một ngoại lệ được kiểm tra. Nếu khách hàng không thể làm gì để khôi phục ngoại lệ, hãy biến nó thành ngoại lệ không được kiểm tra

Trung tâm của "loại ngoại lệ nào để ném" là ngữ nghĩa (ở một mức độ nào đó) và trích dẫn trên cung cấp và hướng dẫn tuyệt vời (do đó, tôi vẫn bị thổi phồng bởi khái niệm rằng C # đã loại bỏ các ngoại lệ được kiểm tra - đặc biệt như Liskov lập luận cho tính hữu dụng của chúng).

Phần còn lại sau đó trở nên hợp lý: trình biên dịch nào mong tôi trả lời, rõ ràng? Những người mà bạn mong đợi khách hàng sẽ phục hồi.


5

Để trả lời câu hỏi cuối cùng (những câu hỏi khác dường như đã trả lời kỹ lưỡng ở trên), "Tôi có nên đưa ra ngoại lệ chính xác hoặc che giấu nó bằng Exception không?"

Tôi giả sử bạn có ý nghĩa như thế này:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Không, luôn luôn tuyên bố ngoại lệ chính xác nhất có thể, hoặc một danh sách như vậy. Các trường hợp ngoại lệ bạn khai báo phương thức của bạn là có khả năng ném là một phần của hợp đồng giữa phương thức của bạn và người gọi. Ném "FileNotFoundException"có nghĩa là có thể tên tệp không hợp lệ và tệp sẽ không được tìm thấy; người gọi sẽ cần xử lý một cách thông minh. Ném Exceptioncó nghĩa là "Này, sh * t xảy ra. Thỏa thuận." Đó là một người rất nghèo API.

Trong các bình luận về bài viết đầu tiên, có một số ví dụ trong đó "ném Exception" là một tuyên bố hợp lệ và hợp lý, nhưng đó không phải là trường hợp của hầu hết normalmã "" mà bạn sẽ viết.


Chính xác, làm cho phần khai báo ngoại lệ kiểm tra của bạn trong tài liệu mã của bạn cũng như giúp đỡ người sử dụng phần mềm của bạn.
Salvador Valencia

5

Ngoại lệ thời gian chạy : Ngoại lệ thời gian chạy được coi là ngoại lệ không được kiểm soát. Tất cả các ngoại lệ khác được kiểm tra ngoại lệ và chúng không xuất phát từ java.lang.R nbException.

Đã kiểm tra ngoại lệ trường hợp ngoại lệ được kiểm tra: Một ngoại lệ được kiểm tra phải được bắt gặp ở đâu đó trong mã của bạn. Nếu bạn gọi một phương thức đưa ra một ngoại lệ được kiểm tra nhưng bạn không bắt được ngoại lệ được kiểm tra ở đâu đó, mã của bạn sẽ không biên dịch. Đó là lý do tại sao chúng được gọi là ngoại lệ được kiểm tra: trình biên dịch kiểm tra để đảm bảo rằng chúng được xử lý hoặc khai báo.

Một số phương thức trong API Java ném các ngoại lệ được kiểm tra, do đó bạn sẽ thường viết các trình xử lý ngoại lệ để đối phó với các ngoại lệ được tạo bởi các phương thức bạn không viết.


3

Tại sao họ để bong bóng ngoại lệ lên? Không xử lý lỗi sớm hơn tốt hơn? Tại sao bong bóng lên?

Ví dụ: giả sử bạn có một số ứng dụng máy chủ-máy khách và máy khách đã đưa ra yêu cầu về một số tài nguyên không thể tìm ra hoặc đối với một lỗi nào khác có thể xảy ra ở phía máy chủ trong khi xử lý yêu cầu của người dùng thì đó là nhiệm vụ của máy chủ để nói với khách hàng lý do tại sao anh ta không thể nhận được thứ anh ta yêu cầu, vì vậy để đạt được điều đó ở phía máy chủ, mã được viết để ném ngoại lệ bằng cách sử dụng từ khóa throw thay vì nuốt hoặc xử lý nó. Nếu máy chủ xử lý / nuốt Sau đó, sẽ không có cơ hội để đe dọa khách hàng rằng những gì đã xảy ra lỗi.

Lưu ý: Để đưa ra một mô tả rõ ràng về loại lỗi đã xảy ra, chúng ta có thể tạo đối tượng Ngoại lệ của riêng mình và ném nó cho máy khách.


Điểm tốt. Điều đó có nghĩa là để bong bóng nó lên lớp có trách nhiệm cao nhất kiểm soát luồng logic và giám sát logic nghiệp vụ cho ứng dụng. Chẳng hạn, lớp cơ sở dữ liệu có thể giao tiếp với khách hàng rằng một cái gì đó quan trọng bị thiếu hoặc không phản hồi. Khi nó sủi bọt lên đến tầng trên cùng của máy chủ thì nó sẽ thẳng tiến để làm mới khung nhìn của máy khách với một thông báo lỗi nghiêm trọng.
Salvador Valencia

3

Tôi nghĩ rằng các ngoại lệ được kiểm tra là một lời nhắc tốt cho nhà phát triển sử dụng thư viện bên ngoài rằng mọi thứ có thể sai với mã từ thư viện đó trong các tình huống đặc biệt.

Đọc thêm về các trường hợp ngoại lệ được kiểm tra và không được kiểm tra tại đây http://learnjava.today/2015/11/checked-vs-unchecked-exceptions/


3

Tôi chỉ muốn thêm một số lý do cho việc không sử dụng ngoại lệ được kiểm tra nào cả. Đây không phải là một câu trả lời đầy đủ, nhưng tôi cảm thấy nó trả lời một phần câu hỏi của bạn và bổ sung cho nhiều câu trả lời khác.

Bất cứ khi nào ngoại lệ được kiểm tra có liên quan, có throws CheckedExceptionmột chữ ký phương thức nào đó ( CheckedExceptioncó thể là bất kỳ ngoại lệ được kiểm tra nào). Chữ ký KHÔNG ném Ngoại lệ, ném Ngoại lệ là một khía cạnh của việc thực hiện. Giao diện, chữ ký phương thức, lớp cha, tất cả những điều này KHÔNG nên phụ thuộc vào việc triển khai của chúng. Việc sử dụng các Ngoại lệ được kiểm tra ở đây (thực tế là bạn phải khai báo throwschữ ký phương thức) đang ràng buộc các giao diện cấp cao hơn với việc triển khai các giao diện này.

Hãy để tôi chỉ cho bạn một ví dụ.

Hãy có một giao diện đẹp và sạch sẽ như thế này

public interface IFoo {
    public void foo();
}

Bây giờ chúng ta có thể viết nhiều triển khai phương thức foo(), như thế này

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Lớp Foo hoàn toàn ổn. Bây giờ hãy thực hiện một nỗ lực đầu tiên tại lớp Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Lớp Bar này sẽ không được biên dịch. Vì InterruptedException là một ngoại lệ được kiểm tra, bạn phải nắm bắt nó (với phương thức thử bắt bên trong foo ()) hoặc tuyên bố rằng bạn đang ném nó (thêm throws InterruptedExceptionvào chữ ký phương thức). Vì tôi không muốn nắm bắt ngoại lệ này ở đây (tôi muốn nó lan truyền lên trên để tôi có thể giải quyết vấn đề này ở nơi khác), hãy thay đổi chữ ký.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Lớp Bar này sẽ không được biên dịch! Phương thức của Bar foo () KHÔNG ghi đè phương thức của IFoo foo () vì chữ ký của chúng khác nhau. Tôi có thể xóa chú thích @Override, nhưng tôi muốn lập trình dựa trên giao diện IFoo thích IFoo foo;và sau đó quyết định xem tôi muốn sử dụng triển khai nào, như thế nào foo = new Bar();. Nếu phương thức của Bar foo () không ghi đè phương thức của IFoo foo, thì khi tôi thực hiện, foo.foo();nó sẽ không gọi triển khai foo () của Bar.

Để làm cho thanh public void foo() throws InterruptedExceptionghi đè của IFoo, public void foo()tôi PHẢI thêm throws InterruptedExceptionvào chữ ký phương thức của IFoo. Tuy nhiên, điều này sẽ gây ra sự cố với lớp Foo của tôi, vì chữ ký của phương thức foo () khác với chữ ký phương thức của IFoo. Hơn nữa, nếu tôi thêm vào throws InterruptedExceptionphương thức của Foo foo () tôi sẽ gặp một lỗi khác nói rằng phương thức của Foo foo () tuyên bố rằng nó ném InterruptedException nhưng nó không bao giờ ném InterruptedException.

Như bạn có thể thấy (nếu tôi đã làm tốt công việc giải thích nội dung này), thực tế là tôi đang ném một ngoại lệ được kiểm tra như InterruptedException đang buộc tôi buộc giao diện IFoo của mình vào một trong những triển khai của nó, điều này gây ra sự tàn phá cho IFoo thực hiện khác!

Đây là một lý do lớn tại sao các ngoại lệ được kiểm tra là BAD. Trong mũ.

Một giải pháp là nắm bắt ngoại lệ được kiểm tra, bọc nó trong một ngoại lệ không được kiểm tra và ném ngoại lệ không được kiểm tra.


2
Vâng, nó tệ bởi vì bạn nói rằng bạn không muốn bắt nó. Nhưng để tránh ảnh hưởng đến chữ ký của IFOO, bạn sẽ phải. Tôi thà làm điều đó và tiếp tục thay vì cân bằng lại tất cả các chữ ký giao diện của mình để tránh bắt ngoại lệ (chỉ vì ngoại lệ là BAD).
Salvador Valencia

Vâng tôi đồng ý. Tôi đã có một chút không rõ ràng về một cái gì đó. Tôi muốn một ngoại lệ để tuyên truyền, vì vậy tôi có thể đối phó với nó ở một nơi khác. Một giải pháp là bắt InterruptedException và đưa ra một ngoại lệ không được kiểm soát. tức là chúng tôi tránh các ngoại lệ được kiểm tra và vượt qua các ngoại lệ không được kiểm tra (ngay cả khi chúng chỉ có ý nghĩa như một trình bao bọc)
Blueriver

"Tuy nhiên, điều này sẽ gây ra vấn đề với lớp Foo của tôi, vì chữ ký của phương thức foo () khác với chữ ký phương thức của IFoo". Tôi vừa thử nghiệm ý tưởng của bạn và có thể biên dịch ngay cả khi chúng tôi thêm throws InterruptedExceptionchữ ký phương thức của IFoo mà không ném bất kỳ thứ gì vào bất kỳ triển khai nào. Vì vậy, nó không thực sự gây ra bất kỳ vấn đề. Nếu trong một giao diện bạn thực hiện mỗi lần ném chữ ký phương thức Exception, nó chỉ cung cấp cho việc triển khai lựa chọn ném hoặc không ném ngoại lệ (bất kỳ ngoại lệ nào, như Exceptiongói gọn tất cả các ngoại lệ).
Flyout91

Tuy nhiên, tôi thừa nhận rằng điều đó có thể gây nhầm lẫn bởi vì khi bạn sẽ triển khai một vùng không gian như vậy và nhấp vào một cái gì đó như "Thêm phương thức chưa thực hiện", chúng sẽ được tạo tự động với throw Exceptionmệnh đề trong chữ ký của chúng, mặc dù việc triển khai của bạn sẽ không ném bất cứ thứ gì hoặc có thể một ngoại lệ cụ thể hơn. Nhưng tôi vẫn cảm thấy như đó là một cách thực hành tốt để luôn ném Ngoại lệ cho phương thức của Giao diện bởi vì, một lần nữa, nó cho người dùng lựa chọn ném hoặc không ném bất cứ thứ gì.
Flyout91

Điều này bỏ lỡ toàn bộ điểm. Mục đích của giao diện là khai báo hợp đồng mà khách hàng yêu cầu phải hài lòng. Điều này có thể bao gồm các kịch bản thất bại mà nó có thể xử lý. Khi một triển khai gặp lỗi, nó sẽ ánh xạ lỗi đó đến lỗi trừu tượng thích hợp được giao diện máy khách khai báo.
erickson

3
  • Java phân biệt giữa hai loại ngoại lệ (được kiểm tra & không được kiểm tra).
  • Java thực thi một yêu cầu bắt hoặc khai báo cho các ngoại lệ được kiểm tra.
  • Một loại ngoại lệ xác định xem một ngoại lệ được kiểm tra hay không được kiểm tra.
  • Tất cả các loại ngoại lệ là trực tiếp hoặc gián tiếp subclassescủa lớp RuntimeException đều là ngoại lệ không được kiểm tra.
  • Tất cả các lớp kế thừa từ lớp Exceptionnhưng không RuntimeExceptionđược coi làchecked exceptions .
  • Các lớp kế thừa từ Lỗi lớp được coi là không được kiểm tra.
  • Trình biên dịch kiểm tra từng lệnh gọi và giảm tốc của phương thức để xác định xem phương thức có ném hay không checked exception.
    • Nếu vậy trình biên dịch đảm bảo ngoại lệ được bắt hoặc được khai báo trong mệnh đề ném.
  • Để đáp ứng phần khai báo của yêu cầu bắt hoặc khai báo, phương thức tạo ngoại lệ phải cung cấp một throwsmệnh đề có chứa checked-exception.
  • Exception các lớp được định nghĩa để được kiểm tra khi chúng được coi là đủ quan trọng để bắt hoặc khai báo.

2

Đây là một quy tắc đơn giản có thể giúp bạn quyết định. Nó liên quan đến cách các giao diện được sử dụng trong Java.

Lấy lớp của bạn và tưởng tượng thiết kế một giao diện cho nó sao cho giao diện mô tả chức năng của lớp nhưng không có cách triển khai cơ bản nào (như một giao diện nên). Giả vờ có lẽ bạn có thể thực hiện lớp theo cách khác.

Nhìn vào các phương thức của giao diện và xem xét các ngoại lệ mà họ có thể đưa ra:

Nếu một ngoại lệ có thể được ném bởi một phương thức, bất kể việc triển khai cơ bản (nói cách khác, nó chỉ mô tả chức năng) thì có lẽ đó phải là một ngoại lệ được kiểm tra trong giao diện.

Nếu một ngoại lệ được gây ra bởi việc triển khai cơ bản, thì nó không nên có trong giao diện. Do đó, nó phải là một ngoại lệ không được kiểm tra trong lớp của bạn (vì các ngoại lệ không được kiểm tra không cần xuất hiện trong chữ ký giao diện) hoặc bạn phải bọc nó và suy nghĩ lại như một ngoại lệ được kiểm tra là một phần của phương thức giao diện.

Để quyết định xem bạn có nên bao bọc và suy nghĩ lại hay không, bạn nên xem xét lại xem liệu người dùng giao diện có phải xử lý tình trạng ngoại lệ ngay lập tức hay không, ngoại lệ quá chung chung đến mức bạn không thể làm gì về nó và nó nên làm gì tuyên truyền lên ngăn xếp. Liệu ngoại lệ được bao bọc có ý nghĩa khi được biểu thị như chức năng của giao diện mới mà bạn đang xác định hoặc nó chỉ là một nhà cung cấp cho một túi các điều kiện lỗi có thể xảy ra với các phương thức khác? Nếu trước đây, nó vẫn có thể là một ngoại lệ được kiểm tra, nếu không nó sẽ bị bỏ chọn.

Bạn thường không nên lập kế hoạch cho các trường hợp ngoại lệ "bong bóng" (bắt và suy nghĩ lại). Người gọi phải xử lý một ngoại lệ (trong trường hợp đó là kiểm tra) hoặc nó sẽ chuyển sang trình xử lý cấp cao (trong trường hợp đó là dễ nhất nếu không được chọn).


2

Chỉ cần chỉ ra rằng nếu bạn ném một ngoại lệ được kiểm tra vào mã và mức bắt ở một vài mức ở trên, bạn cần khai báo ngoại lệ trong chữ ký của từng phương thức giữa bạn và lệnh bắt. Vì vậy, đóng gói bị phá vỡ vì tất cả các chức năng trong đường ném phải biết về chi tiết của ngoại lệ đó.


2

Nói tóm lại, các ngoại lệ mà mô-đun hoặc mô-đun của bạn ở trên được cho là xử lý trong thời gian chạy được gọi là ngoại lệ được kiểm tra; những trường hợp khác không được kiểm tra ngoại lệ là RuntimeExceptionhoặc Error.

Trong video này, nó giải thích các ngoại lệ được kiểm tra và không được kiểm tra trong Java:
https://www.youtube.com/watch?v=ue2pOqLaArw


1

Tất cả những người được kiểm tra ngoại lệ. Các ngoại lệ không được kiểm tra là các lớp con của RuntimeException. Quyết định không phải là làm thế nào để xử lý chúng, mã của bạn có nên ném chúng không. Nếu bạn không muốn trình biên dịch nói với bạn rằng bạn chưa xử lý một ngoại lệ thì bạn sử dụng một ngoại lệ (lớp con của RuntimeException) không được kiểm tra. Chúng nên được lưu cho các tình huống mà bạn không thể phục hồi, như lỗi bộ nhớ và tương tự.


ừm nếu NumberFormatException là một ngoại lệ được kiểm tra, như bạn nói, không phải nó mâu thuẫn với thực tế là nó được kế thừa từ RuntimeException ?
eis

Xin lỗi, tôi không rõ lắm. Tôi đã đề cập đến FileNotFoundException chứ không phải NumberFormatException. Dựa trên # 2 & # 4 của anh ấy, có vẻ như anh ấy nghĩ rằng Kiểm tra so với Không được kiểm tra dựa trên cách bạn xử lý ngoại lệ sau khi bắt được nó. Không phải nó được định nghĩa như thế nào.
mamboking

-1

Nếu bất kỳ ai quan tâm đến một bằng chứng khác để không thích các ngoại lệ được kiểm tra, hãy xem một vài đoạn đầu tiên của thư viện JSON phổ biến:

"Mặc dù đây là một ngoại lệ được kiểm tra, nhưng nó hiếm khi có thể phục hồi được. Hầu hết người gọi chỉ nên bọc ngoại lệ này trong một ngoại lệ không được kiểm tra và suy nghĩ lại:"

Vậy tại sao trên thế giới có ai khiến các nhà phát triển tiếp tục kiểm tra ngoại lệ, thay vào đó chúng ta nên "đơn giản là bọc nó"? cười lớn

http://developer.android.com/reference/org/json/JSONException.html


4
Bởi vì nó chỉ là hầu hết người gọi, không phải tất cả người gọi, nên bao bọc và suy nghĩ lại. Thực tế là ngoại lệ được kiểm tra có nghĩa là người gọi phải suy nghĩ xem họ là một trong những người gọi "nhất" hay là một trong những nhóm thiểu số có thể và nên xử lý ngoại lệ đó.
Warren Dew

1
Nếu bạn muốn kiểm tra lỗi cho mỗi cuộc gọi bạn thực hiện, "quay lại" với C. Ngoại lệ là một cách để tách việc thực thi chương trình bình thường khỏi bất thường, mà không làm ô nhiễm mã của bạn. Các ngoại lệ đảm bảo bạn không thể bỏ qua một lỗi âm thầm ở một mức độ nào đó .
Slawomir

-1

Đã kiểm tra ngoại lệ :

  • Các ngoại lệ được trình biên dịch kiểm tra để thực thi trơn tru chương trình khi chạy được gọi là Ngoại lệ được kiểm tra.

  • Những điều này xảy ra tại thời gian biên dịch.

  • Nếu những điều này không được xử lý đúng cách, chúng sẽ đưa ra lỗi thời gian biên dịch (Không phải ngoại lệ).
  • Tất cả các lớp con của lớp Exception ngoại trừ RuntimeException đều được kiểm tra Ngoại lệ.

    Ví dụ giả thuyết - Giả sử bạn rời khỏi nhà để thi, nhưng nếu bạn kiểm tra xem bạn đã lấy Vé Hội trường ở nhà chưa (thời gian biên dịch) thì sẽ không có vấn đề gì ở Hội trường thi (thời gian chạy).

Ngoại lệ không được kiểm tra :

  • Các ngoại lệ không được kiểm tra bởi trình biên dịch được gọi là Ngoại lệ không được kiểm tra.

  • Những điều này xảy ra trong thời gian chạy.

  • Nếu các ngoại lệ này không được xử lý đúng cách, chúng sẽ không gây ra lỗi thời gian biên dịch. Nhưng chương trình sẽ bị chấm dứt sớm khi chạy.

  • Tất cả các lớp con của RunTimeException và Error đều không được kiểm tra ngoại lệ.

    Ví dụ giả thuyết - Giả sử bạn đang ở trong phòng thi của mình nhưng bằng cách nào đó trường bạn gặp tai nạn hỏa hoạn (có nghĩa là trong thời gian chạy), nơi bạn không thể làm gì vào lúc đó nhưng có thể thực hiện các biện pháp phòng ngừa trước (thời gian biên dịch).


-2

Tất cả các ngoại lệ phải được kiểm tra ngoại lệ.

  1. Ngoại lệ không được kiểm tra là gotos không giới hạn. Và gotos không hạn chế được coi là một điều xấu.

  2. Ngoại lệ không được kiểm soát phá vỡ đóng gói. Để xử lý chúng một cách chính xác, tất cả các chức năng trong cây cuộc gọi giữa người ném và người bắt phải được biết để tránh lỗi.

  3. Trường hợp ngoại lệ là lỗi trong hàm ném chúng nhưng không phải lỗi trong hàm xử lý chúng. Mục đích của các trường hợp ngoại lệ là cung cấp cho chương trình cơ hội thứ hai bằng cách trì hoãn quyết định xem đó có phải là lỗi hay không đối với bối cảnh khác. Chỉ trong bối cảnh khác, quyết định chính xác mới có thể được đưa ra.

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.