1. Exception Handling
1.1 Introduction
Một ngoại lệ là một sự kiện bất thường phát sinh trong quá trình thực hiện chương trình và làm gián đoạn dòng chảy bình thường của chương trình. Bất thường xảy ra khi chương trình của bạn đang chạy. Ví dụ: bạn có thể mong đợi người dùng nhập số nguyên, nhưng nhận được chuỗi văn bản; hoặc một lỗi I / O bất ngờ xuất hiện khi chạy. Điều thực sự quan trọng là "điều gì xảy ra sau khi bất thường xảy ra?" Nói cách khác, "làm thế nào các tình huống bất thường được xử lý bởi chương trình của bạn." Nếu những ngoại lệ này không được xử lý đúng cách, chương trình sẽ chấm dứt đột ngột và có thể gây ra hậu quả nghiêm trọng. Ví dụ: các kết nối mạng, kết nối cơ sở dữ liệu và tệp có thể vẫn được mở; cơ sở dữ liệu và hồ sơ tập tin có thể được để lại trong một trạng thái không nhất quán.
Java có một cơ chế tích hợp để xử lý các lỗi thời gian chạy, được gọi là xử lý ngoại lệ . Điều này là để đảm bảo rằng bạn có thể viết các chương trình mạnh mẽ cho các ứng dụng quan trọng.
Các ngôn ngữ lập trình cũ hơn như C có một số nhược điểm trong việc xử lý ngoại lệ. Ví dụ: giả sử lập trình viên muốn mở tệp để xử lý:
- Các lập trình viên không được thực hiện để nhận thức được các điều kiện đặc biệt. Ví dụ, tập tin được mở có thể không nhất thiết tồn tại. Do đó, lập trình viên không viết mã để kiểm tra xem tệp có tồn tại hay không trước khi mở tệp.
- Giả sử lập trình viên nhận thức được các điều kiện đặc biệt, anh ấy / cô ấy có thể quyết định hoàn thành logic chính trước và viết mã xử lý ngoại lệ sau - điều này "sau", thật không may, thường không bao giờ xảy ra. Nói cách khác, bạn không bắt buộc phải viết mã xử lý ngoại lệ cùng với logic chính.
- Giả sử lập trình viên quyết định viết mã xử lý ngoại lệ, mã xử lý ngoại lệ đan xen với logic chính trong nhiều câu lệnh if-other. Điều này làm cho logic chính khó theo dõi và toàn bộ chương trình khó đọc. Ví dụ,
if (file exists) { open file; while (there is more records to be processed) { if (no IO errors) { process the file record } else { handle the errors } } if (file is opened) close the file; } else { report the file does not exist; }
Java khắc phục những nhược điểm này bằng cách xây dựng xử lý ngoại lệ thành ngôn ngữ thay vì để nó theo ý của các lập trình viên:
- Bạn sẽ được thông báo về các điều kiện đặc biệt có thể phát sinh khi gọi một phương thức - Các ngoại lệ được khai báo trong chữ ký của phương thức.
- Bạn bị buộc phải xử lý các trường hợp ngoại lệ trong khi viết logic chính và không thể để chúng như một suy nghĩ sau - Chương trình của bạn không thể được biên dịch mà không có mã xử lý ngoại lệ.
- Mã xử lý ngoại lệ được tách ra khỏi logic chính - Thông qua
try-catch-finally
cấu trúc.
Hãy xem xét ba điểm này chi tiết hơn.
Điểm 1: Ngoại lệ phải được khai báo
Ví dụ: giả sử bạn muốn sử dụng một
java.util.Scanner
để thực hiện định dạng đầu vào từ một tệp đĩa. Chữ ký của hàm Scanner
tạo với một File
đối số được đưa ra như sau:public Scanner(File source) throws FileNotFoundException;
Chữ ký của phương thức thông báo cho các lập trình viên rằng một điều kiện đặc biệt "không tìm thấy tệp" có thể phát sinh. Bằng cách khai báo các ngoại lệ trong chữ ký của phương thức, các lập trình viên được tạo ra để nhận biết các điều kiện đặc biệt trong việc sử dụng phương thức.
Điểm 2: Ngoại lệ phải được xử lý
Nếu một phương thức khai báo một ngoại lệ trong chữ ký của nó, bạn không thể sử dụng phương thức này mà không xử lý ngoại lệ đó - bạn không thể biên dịch chương trình.
Ví dụ 1: Chương trình không xử lý ngoại lệ được khai báo, được nối lại trong lỗi biên dịch.
import java.util.Scanner; import java.io.File; public class ScannerFromFile { public static void main(String[] args) { Scanner in = new Scanner(new File("test.in")); // do something ... } }
ScannerFromFile.java:5: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown
Scanner in = new Scanner(new File("test.in"));
^
Để sử dụng một phương thức khai báo một ngoại lệ trong chữ ký của nó, bạn PHẢI:
- cung cấp mã xử lý ngoại lệ trong cấu trúc "
try-catch
" hoặc "try-catch-finally
" hoặc - không xử lý ngoại lệ trong phương thức hiện tại, nhưng khai báo ngoại lệ sẽ được đưa lên ngăn xếp cuộc gọi để phương thức cấp cao hơn tiếp theo xử lý.
Ví dụ 2: Bắt ngoại lệ thông qua cấu trúc "
try-catch
" (hoặc " try-catch-finally
").import java.util.Scanner; import java.io.File; import java.io.FileNotFoundException; public class ScannerFromFileWithCatch { public static void main(String[] args) { try { Scanner in = new Scanner(new File("test.in")); // do something if no exception ... // you main logic here in the try-block } catch (FileNotFoundException ex) { // error handling separated from the main logic ex.printStackTrace(); // print the stack trace } } }
Nếu tập tin không thể được tìm thấy, ngoại lệ được bắt trong khối catch. Trong ví dụ này, trình xử lý lỗi chỉ cần in dấu vết ngăn xếp , cung cấp thông tin hữu ích để gỡ lỗi. Trong một số trường hợp, bạn có thể cần thực hiện một số thao tác dọn dẹp hoặc mở tệp khác thay thế. Xin lưu ý rằng logic chính trong khối thử được tách biệt với các mã xử lý lỗi trong khối catch.
Ví dụ 3: Bạn đã quyết định không xử lý ngoại lệ trong phương thức hiện tại, nhưng ném ngoại lệ lên ngăn xếp cuộc gọi cho phương thức cấp cao hơn tiếp theo để xử lý.
import java.util.Scanner; import java.io.File; import java.io.FileNotFoundException; public class ScannerFromFileWithThrow { public static void main(String[] args) throws FileNotFoundException { // to be handled by next higher-level method Scanner in = new Scanner(new File("test.in")); // this method may throw FileNotFoundException // main logic here ... } }
Trong ví dụ này, bạn đã quyết định không xử lý việc
FileNotFoundException
ném theo phương thức Scanner(File)
(với try-catch
). Thay vào đó, phần gọi của Scanner(File)
- main()
phương thức - khai báo chữ ký " throws FileNotFoundException
", có nghĩa là ngoại lệ này sẽ được đưa lên ngăn xếp cuộc gọi, để xử lý phương thức cấp cao hơn tiếp theo. Trong trường hợp này, phương thức cấp cao hơn tiếp theo main()
là JVM, đơn giản là chấm dứt chương trình và in dấu vết ngăn xếp.Điểm 3: Logic chính được tách ra khỏi các mã xử lý ngoại lệ
Như được hiển thị trong Ví dụ 2, logic chính được chứa trong khối try, trong khi các mã xử lý ngoại lệ được giữ trong (các) khối catch tách biệt với logic chính. Điều này cải thiện đáng kể khả năng đọc của chương trình.
Ví dụ, một chương trình Java để xử lý tệp có thể như sau:
try { // Main logic here open file; process file; ...... } catch (FileNotFoundException ex) { // Exception handlers below // Exception handler for "file not found" } catch (IOException ex) { // Exception handler for "IO errors" } finally { close file; // always try to close the file }
1.2 Method Call Stack
Một ứng dụng điển hình bao gồm nhiều cấp độ của các cuộc gọi phương thức, được quản lý bởi một ngăn xếp cuộc gọi phương thức . Một ngăn xếp là một hàng đợi vào trước ra trước . Trong ví dụ sau,
main()
phương thức gọi methodA()
; methodA()
các lời gọi methodB()
; methodB()
các lời gọi methodC()
.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class MethodCallStackDemo { public static void main(String[] args) { System.out.println("Enter main()"); methodA(); System.out.println("Exit main()"); } public static void methodA() { System.out.println("Enter methodA()"); methodB(); System.out.println("Exit methodA()"); } public static void methodB() { System.out.println("Enter methodB()"); methodC(); System.out.println("Exit methodB()"); } public static void methodC() { System.out.println("Enter methodC()"); System.out.println("Exit methodC()"); } } |
Enter main() Enter methodA() Enter methodB() Enter methodC() Exit methodC() Exit methodB() Exit methodA() Exit main()
Nhìn từ đầu ra, chuỗi các sự kiện là:
- JVM gọi
main()
. main()
đẩy lên ngăn xếp cuộc gọi, trước khi gọimethodA()
.methodA()
đẩy lên ngăn xếp cuộc gọi, trước khi gọimethodB()
.methodB()
đẩy lên ngăn xếp cuộc gọi, trước khi gọimethodC()
.methodC()
hoàn thànhmethodB()
bật ra từ ngăn xếp cuộc gọi và hoàn thành.methodA()
bật ra từ ngăn xếp cuộc gọi và hoàn thành.main()
bật ra từ ngăn xếp cuộc gọi và hoàn thành. Chương trình thoát.
Giả sử rằng chúng tôi sửa đổi
methodC()
để thực hiện thao tác "chia cho 0", kích hoạt ArithmeticException
:public static void methodC() {
System.out.println("Enter methodC()");
System.out.println(1 / 0); // divide-by-0 triggers an ArithmeticException
System.out.println("Exit methodC()");
}
Thông báo ngoại lệ hiển thị rõ ràng dấu vết ngăn xếp cuộc gọi phương thức với các số dòng câu lệnh liên quan:
Enter main() Enter methodA() Enter methodB() Enter methodC() Exception in thread "main" java.lang.ArithmeticException: / by zero at MethodCallStackDemo.methodC(MethodCallStackDemo.java:22) at MethodCallStackDemo.methodB(MethodCallStackDemo.java:16) at MethodCallStackDemo.methodA(MethodCallStackDemo.java:10) at MethodCallStackDemo.main(MethodCallStackDemo.java:4)
MethodC()
kích hoạt một ArithmeticException
. Vì nó không xử lý ngoại lệ này, nó bật ra khỏi ngăn xếp cuộc gọi ngay lập tức. MethodB()
cũng không xử lý ngoại lệ này và bật ra khỏi ngăn xếp cuộc gọi. Vì vậy, hiện methodA()
và main()
phương pháp. Các main()
phương pháp họ sẽ trả lại cho JVM, mà đột ngột chấm dứt chương trình và in các cuộc gọi stack dấu vết, như thể hiện.1.3 Exception & Call Stack
Khi một ngoại lệ xảy ra bên trong một phương thức Java, phương thức này tạo ra một
Exception
đối tượng và chuyển Exception
đối tượng cho JVM (theo thuật ngữ Java, phương thức " throw
" an Exception
). Đối Exception
tượng chứa loại ngoại lệ và trạng thái của chương trình khi ngoại lệ xảy ra. JVM chịu trách nhiệm tìm một trình xử lý ngoại lệ để xử lýException
đối tượng. Nó tìm kiếm ngược thông qua ngăn xếp cuộc gọi cho đến khi tìm thấy một trình xử lý ngoại lệ phù hợp cho lớp Exception
đối tượng cụ thể đó (theo thuật ngữ Java, nó được gọi là " catch
" the Exception
). Nếu JVM không thể tìm thấy trình xử lý ngoại lệ phù hợp trong tất cả các phương thức trong ngăn xếp cuộc gọi, nó sẽ chấm dứt chương trình.
Quá trình này được minh họa như sau. Giả sử rằng
methodD()
gặp một điều kiện bất thường và ném a XxxException
vào JVM. JVM tìm kiếm ngược thông qua ngăn xếp cuộc gọi để xử lý ngoại lệ phù hợp. Nó tìm thấy methodA()
có một XxxException
trình xử lý và chuyển đối tượng ngoại lệ cho trình xử lý. Lưu ý rằng methodC()
và methodB()
được yêu cầu khai báo " throws XxxException"
trong chữ ký phương thức của họ để biên dịch chương trình.1.4 Exception Classes - Throwable, Error, Exception & RuntimeException
Hình dưới đây cho thấy sự phân cấp của các
Exception
lớp. Lớp cơ sở cho tất cả Exception
các đối tượng là java.lang.Throwable
, cùng với hai lớp con java.lang.Exception
và java.lang.Error
.- Các
Error
lớp mô tả lỗi hệ thống nội bộ (ví dụVirtualMachineError
,LinkageError
) mà hiếm khi xảy ra. Nếu xảy ra lỗi như vậy, có rất ít điều bạn có thể làm và chương trình sẽ bị chấm dứt bởi thời gian chạy Java. - Các
Exception
lớp mô tả các lỗi gây ra bởi chương trình của bạn (ví dụFileNotFoundException
,IOException
). Các lỗi này có thể bị chương trình của bạn bắt và xử lý (ví dụ: thực hiện một hành động thay thế hoặc thực hiện một lối thoát duyên dáng bằng cách đóng tất cả các tệp, kết nối mạng và cơ sở dữ liệu). - Tuyên bố ngoại lệ;
- Ném một ngoại lệ; và
- Bắt một ngoại lệ.
1.5 Các trường hợp ngoại lệ được kiểm tra và không được kiểm tra
Như được minh họa, các lớp con của
Error
và RuntimeException
được gọi là ngoại lệ không được kiểm tra . Các ngoại lệ này không được kiểm tra bởi trình biên dịch, và do đó, không cần phải bị bắt hoặc khai báo sẽ bị ném trong chương trình của bạn. Điều này là do bạn không thể làm gì nhiều với những ngoại lệ này. Ví dụ: "chia cho 0" kích hoạt một ArithmeticException
, chỉ mục mảng ngoài giới hạn kích hoạt một ArrayIndexOutOfBoundException,
lỗi logic lập trình thực sự sẽ được sửa trong thời gian biên dịch, thay vì xử lý ngoại lệ thời gian chạy.
Tất cả các ngoại lệ khác được gọi là ngoại lệ được kiểm tra . Chúng được kiểm tra bởi trình biên dịch và phải được bắt hoặc khai báo để ném.
1.6 Hoạt động xử lý ngoại lệ
Năm từ khóa được sử dụng trong xử lý ngoại lệ:
try
, catch
, finally
, throws
và throw
(lưu ý rằng có một sự khác biệt giữa throw
và throws
).
Xử lý ngoại lệ của Java bao gồm ba hoạt động:
Khai báo ngoại lệ
Một phương thức Java phải khai báo trong chữ ký của nó các loại ngoại lệ được kiểm tra mà nó có thể "ném" khỏi cơ thể của nó, thông qua từ khóa "throws".
Ví dụ: giả sử
methodD()
được xác định như sau:public void methodD() throws XxxException, YyyException { // method body throw XxxException and YyyException }
Chữ ký của phương thức chỉ ra rằng việc chạy
methodD()
có thể gặp hai ngoại lệ được kiểm tra: XxxException
và YyyException
. Nói cách khác, một số điều kiện bất thường bên trong methodD()
có thể kích hoạt XxxException
hoặc YyyException
.
Ngoại lệ thuộc
Error
, RuntimeException
và họ lớp con không cần phải được công bố. Các ngoại lệ này được gọi là ngoại lệ không được kiểm tra vì chúng không được trình biên dịch kiểm tra.Ném một ngoại lệ
Khi một hoạt động Java gặp phải một tình huống bất thường, phương thức chứa câu lệnh sai sẽ tạo ra một
Exception
đối tượng thích hợp và ném nó vào thời gian chạy Java thông qua câu lệnh " throw XxxException
". Ví dụ,public void methodD() throws XxxException, YyyException { // method's signature // method's body ... ... // XxxException occurs if ( ... ) throw new XxxException(...); // construct an XxxException object and throw to JVM ... // YyyException occurs if ( ... ) throw new YyyException(...); // construct an YyyException object and throw to JVM ... }
Lưu ý rằng từ khóa để khai báo ngoại lệ trong chữ ký của phương thức là "
throws
" và từ khóa để ném một đối tượng ngoại lệ trong phần thân của phương thức là " throw
".Bắt ngoại lệ
Khi một phương thức đưa ra một ngoại lệ, JVM sẽ tìm kiếm ngược thông qua ngăn xếp cuộc gọi để xử lý ngoại lệ phù hợp. Mỗi trình xử lý ngoại lệ có thể xử lý một lớp ngoại lệ cụ thể. Một trình xử lý ngoại lệ xử lý một lớp cụ thể cũng có thể xử lý các lớp con của nó . Nếu không tìm thấy trình xử lý ngoại lệ nào trong ngăn xếp cuộc gọi, chương trình sẽ kết thúc.
Ví dụ: giả sử
methodD()
tuyên bố rằng nó có thể ném XxxException
và YyyException
trong chữ ký của nó, như sau:public void methodD() throws XxxException, YyyException { ...... }
- Kết thúc lời gọi
methodD()
bên trong một thử bắt (hoặc thử bắt cuối cùng) như sau. Mỗi khối bắt có thể chứa một trình xử lý ngoại lệ cho một loại ngoại lệ public void methodC() { // no exception declared ...... try { ...... // uses methodD() which declares XxxException & YyyException methodD(); ...... } catch (XxxException ex) { // Exception handler for XxxException ...... } catch (YyyException ex} { // Exception handler for YyyException ...... } finally { // optional // These codes always run, used for cleaning up ...... } ...... }
- Giả sử rằng
methodC()
ai gọimethodD()
không muốn xử lý các ngoại lệ (thông qua một lần thử), nó có thể khai báo các ngoại lệ này để ném lên ngăn xếp cuộc gọi trong chữ ký của nó như sau:public void methodC() throws XxxException, YyyException { // for next higher-level method to handle ... // uses methodD() which declares "throws XxxException, YyyException" methodD(); // no need for try-catch ... }
Trong trường hợp này, nếu mộtXxxException
hoặcYyyException
bị ném bởimethodD()
, JVM sẽ chấm dứtmethodD()
cũng nhưmethodC()
và chuyển đối tượng ngoại lệ lên ngăn xếp cuộc gọi cho người gọi củamethodC()
.
Để sử dụng
methodD()
trong chương trình của bạn (nói trong methodC()
), bạn có thể:1.7 try-catch-finally
The syntax of try-catch-finally is:
try { // main logic, uses methods that may throw Exceptions ...... } catch (Exception1 ex) { // error handler for Exception1 ...... } catch (Exception2 ex) { // error handler for Exception1 ...... } finally { // finally is optional // clean up codes, always executed regardless of exceptions ...... }
Nếu không có ngoại lệ xảy ra trong quá trình chạy khối try, tất cả các khối catch được bỏ qua và khối finally sẽ được thực hiện sau khối try. Nếu một trong các câu lệnh trong khối try đưa ra một ngoại lệ, thì bộ thực thi Java sẽ bỏ qua các câu lệnh còn lại trong khối try và bắt đầu tìm kiếm một trình xử lý ngoại lệ phù hợp. Nó phù hợp với loại ngoại lệ với từng khối catch liên tục . Nếu một khối try bắt lớp ngoại lệ đó hoặc bắt một siêu lớp của ngoại lệ đó, câu lệnh trong khối try đó sẽ được thực thi. Các câu lệnh trong khối finally sau đó được thực hiện sau khối bắt đó. Chương trình tiếp tục vào câu lệnh tiếp theo sau lần thử catch cuối cùng, trừ khi nó được kết thúc trước khi kết thúc hoặc phân nhánh.
Nếu không có kết quả nào
catch
phù hợp, ngoại lệ sẽ được chuyển lên ngăn xếp cuộc gọi. Phương thức hiện tại thực thi finally
mệnh đề (nếu có) và bật ra khỏi ngăn xếp cuộc gọi. Người gọi làm theo các thủ tục tương tự để xử lý ngoại lệ.
Các khối
finally
là gần như chắc chắn được thực thi, bất kể có hay không ngoại lệ xảy ra (trừ khi JVM gặp phải một lỗi nghiêm trọng hay System.exit()
được gọi là trong khối catch
).Example 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import java.util.Scanner; import java.io.File; import java.io.FileNotFoundException; public class TryCatchFinally { public static void main(String[] args) { try { // main logic System.out.println("Start of the main logic"); System.out.println("Try opening a file ..."); Scanner in = new Scanner(new File("test.in")); System.out.println("File Found, processing the file ..."); System.out.println("End of the main logic"); } catch (FileNotFoundException ex) { // error handling separated from the main logic System.out.println("File Not Found caught ..."); } finally { // always run regardless of exception status System.out.println("finally-block runs regardless of the state of exception"); } // after the try-catch-finally System.out.println("After try-catch-finally, life goes on..."); } } |
This is the output when the
FileNotFoundException
triggered:Start of the main logic Try opening a file ... File Not Found caught ... finally-block runs regardless of the state of exception After try-catch-finally, life goes on...
This is the output when no exception triggered:
Start of the main logic Try opening a file ... File Found, processing the file ... End of the main logic finally-block runs regardless of the state of exception After try-catch-finally, life goes on...
Example 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class MethodCallStackDemo { public static void main(String[] args) { System.out.println("Enter main()"); methodA(); System.out.println("Exit main()"); } public static void methodA() { System.out.println("Enter methodA()"); try { System.out.println(1 / 0); // A divide-by-0 triggers an ArithmeticException - an unchecked exception // This method does not catch ArithmeticException // It runs the "finally" and popped off the call stack } finally { System.out.println("finally in methodA()"); } System.out.println("Exit methodA()"); } } |
Enter main() Enter methodA() finally in methodA() Exception in thread "main" java.lang.ArithmeticException: / by zero at MethodCallStackDemo.methodA(MethodCallStackDemo.java:11) at MethodCallStackDemo.main(MethodCallStackDemo.java:4)
try-catch-finally
- Một khối try phải được kèm theo ít nhất một khối catch hoặc khối finally.
- Bạn có thể có nhiều khối catch. Mỗi khối bắt chỉ catch được một loại ngoại lệ.
- Một khối catch yêu cầu một đối số, đó là một
throwable
đối tượng (nghĩa là một lớp con củajava.lang.Throwable
), như sau: catch (AThrowableSubClass aThrowableObject) { // exception handling codes }
- Bạn có thể sử dụng các phương thức sau để lấy loại ngoại lệ và trạng thái của chương trình từ
Throwable
đối tượng:printStackTrace()
: In nàyThrowable
và theo dõi ngăn xếp cuộc gọi của nó vào luồng lỗi tiêu chuẩnSystem.err
. Dòng đầu tiên của kết quả đầu ra chứa kết quảtoString()
và các dòng còn lại là dấu vết ngăn xếp. Đây là xử lý phổ biến nhất, nếu không có gì tốt hơn mà bạn có thể làm. Ví dụ,
- Bạn cũng có thể sử dụng
printStackTrace(PrintStream s)
hoặcprintStackTrace(PrintWriter s)
. getMessage()
: Trả vềmessage
chỉ định nếu đối tượng được xây dựng bằng cách sử dụng hàm tạoThrowable(String message)
.toString()
: Trả về một mô tả ngắn vềThrowable
đối tượng này , bao gồm tên của lớp, dấu hai chấm':'
và một thông báo từgetMessage()
.
- Bạn cũng có thể sử dụng
- Một khối bắt bắt một lớp ngoại lệ cụ thể cũng có thể bắt các lớp con của nó . Do đó,
catch(Exception ex) {...}
bắt tất cả các loại ngoại lệ. Tuy nhiên, đây không phải là một thực tiễn tốt vì trình xử lý ngoại lệ quá chung chung có thể vô tình bắt được một số ngoại lệ của các lớp con mà nó không có ý định. - Thứ tự của các khối bắt là quan trọng. Một lớp con phải được bắt (và đặt ở phía trước) trước khi siêu lớp của nó. Nếu không, bạn nhận được một lỗi biên dịch "ngoại lệ
XxxException
đã bị bắt". - Khối cuối cùng có nghĩa là cho mã dọn dẹp, chẳng hạn như đóng tệp, kết nối cơ sở dữ liệu bất kể khối thử có thành công hay không. Khối cuối cùng luôn được thực thi (trừ khi khối bắt trước kết thúc trước phương thức hiện tại).
try { Scanner in = new Scanner(new File("test.in")); // process the file here ...... } catch (FileNotFoundException ex) { ex.printStackTrace(); }
Điều gì xảy ra nếu tôi thực sự không quan tâm đến các ngoại lệ
Chắc chắn không nên dùng ngoài việc viết chương trình trò chơi. Nhưng để bỏ qua các thông báo lỗi biên dịch được kích hoạt bởi các phương thức khai báo các ngoại lệ không được kiểm tra, bạn có thể khai báo " throws Exception
" trong main()
(và các phương thức khác), như sau:
Chắc chắn không nên dùng ngoài việc viết chương trình trò chơi. Nhưng để bỏ qua các thông báo lỗi biên dịch được kích hoạt bởi các phương thức khai báo các ngoại lệ không được kiểm tra, bạn có thể khai báo "
throws Exception
" trong main()
(và các phương thức khác), như sau:public static void main(String[] args) throws Exception { // throws all subclass of Exception to JRE Scanner in = new Scanner(new File("test.in")); // declares "throws FileNotFoundException" ...... // other exceptions }
Overriding and Overloading Methods
Một phương thức ghi đè phải có cùng danh sách đối số và kiểu trả về (hoặc lớp con của bản gốc từ JDK 1.5). Một phương thức nạp chồng phải có danh sách đối số khác nhau, nhưng nó có thể có bất kỳ kiểu trả về nào.
Một phương thức ghi đè không thể có quyền truy cập hạn chế hơn. Ví dụ: một phương thức có
protected
quyền truy cập có thể bị ghi đè để có quyền truy cập được bảo vệ hoặc công khai nhưng không có private
quyền truy cập mặc định hoặc không có quyền truy cập mặc định. Điều này là do một phương thức ghi đè được coi là thay thế cho phương thức ban đầu của nó, do đó, nó không thể hạn chế hơn.
Phương thức ghi đè không thể khai báo các loại ngoại lệ không được khai báo trong bản gốc. Tuy nhiên, nó có thể khai báo các loại ngoại lệ giống như hoặc lớp con của bản gốc. Nó không cần phải khai báo tất cả các ngoại lệ như bản gốc của nó. Nó có thể ném ít ngoại lệ hơn bản gốc, nhưng không nhiều hơn.
Một phương thức nạp chồng phải được phân biệt bởi danh sách đối số của nó. Nó không thể được phân biệt bởi loại trả về, ngoại lệ và công cụ sửa đổi, đó là bất hợp pháp. Nó có thể có bất kỳ kiểu trả về, sửa đổi truy cập và ngoại lệ nào, miễn là nó có thể được phân biệt bởi danh sách đối số.1.8 Common Exception Classes
ArrayIndexOutOfBoundException : được ném bởi JVM khi mã của bạn sử dụng một chỉ mục mảng, nằm ngoài giới hạn của mảng. Ví dụ,
int[] anArray = new int[3]; System.out.println(anArray[3]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
NullPulumException : được ném bởi JVM khi mã của bạn cố gắng sử dụng tham chiếu null trong đó yêu cầu tham chiếu đối tượng. Ví dụ,
String[] strs = new String[3]; System.out.println(strs[0].length());
Exception in thread "main" java.lang.NullPointerException
NumberFormatException : Ném theo chương trình (ví dụ: bởi
Integer.parseInt()
) khi một nỗ lực được thực hiện để chuyển đổi một chuỗi thành một kiểu số, nhưng chuỗi không có định dạng phù hợp. Ví dụ,Integer.parseInt("abc");
Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
ClassCastException : được ném bởi JVM khi một nỗ lực được thực hiện để truyền tham chiếu đối tượng không thành công. Ví dụ,
Object o = new Object(); Integer i = (Integer)o;
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Integer
IllegalArgumentException : ném theo chương trình để chỉ ra rằng một phương thức đã được thông qua một đối số bất hợp pháp hoặc không phù hợp. Bạn có thể sử dụng lại ngoại lệ này cho các phương thức của riêng bạn.
IllegalStateException : được lập trình ném khi một phương thức được gọi và chương trình không ở trạng thái thích hợp để phương thức đó thực hiện nhiệm vụ của nó. Điều này thường xảy ra khi một phương thức được gọi ra khỏi chuỗi hoặc có lẽ một phương thức chỉ được phép gọi một lần và một nỗ lực được thực hiện để gọi lại nó.
NoClassDefFoundError : được ném bởi JVM hoặc trình nạp lớp khi không thể tìm thấy định nghĩa của một lớp. Trước JDK 1.7, bạn sẽ thấy dấu vết ngăn xếp cuộc gọi ngoại lệ này nếu bạn cố chạy một lớp không tồn tại. JDK 1.7 đơn giản hóa thông báo lỗi thành "Lỗi: Không thể tìm hoặc tải xxx lớp chính".
1.9 Creating Your Own Exception Classes
Bạn nên cố gắng tái sử dụng các
Lưu ý rằng Exception
lớp học được cung cấp trong JDK, ví dụ IndexOutOfBoundException
, ArithmeticException
, IOException
, và IllegalArugmentException
. Nhưng bạn luôn có thể tạo Exception
các lớp riêng của mình bằng cách mở rộng từ lớp Exception
hoặc một trong các lớp con của nó.RuntimeException
và các lớp con của nó không được trình biên dịch kiểm tra và không cần phải khai báo trong chữ ký của phương thức. Do đó, hãy cẩn thận sử dụng chúng, vì bạn sẽ không được thông báo và có thể không nhận thức được các ngoại lệ có thể xảy ra bằng cách sử dụng phương pháp đó (và do đó không có mã xử lý ngoại lệ phù hợp) - một thực hành kỹ thuật phần mềm tồi.Example
1 2 3 4 5 6 | // Create our own exception class by subclassing Exception. This is a checked exception public class MyMagicException extends Exception { public MyMagicException(String message) { //constructor super(message); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class MyMagicExceptionTest { // This method "throw MyMagicException" in its body. // MyMagicException is checked and need to be declared in the method's signature public static void magic(int number) throws MyMagicException { if (number == 8) { throw (new MyMagicException("you hit the magic number")); } System.out.println("hello"); // skip if exception triggered } public static void main(String[] args) { try { magic(9); // does not trigger exception magic(8); // trigger exception } catch (MyMagicException ex) { // exception handler ex.printStackTrace(); } } } |
The output is as follows:
hello MyMagicException: you hit the magic number at MyMagicExceptionTest.magic(MyMagicExceptionTest.java:6) at MyMagicExceptionTest.main(MyMagicExceptionTest.java:14)
إرسال تعليق