Giáo trình Kỹ thuật phần mềm - Chương 4: Xử lý ngoại lệ - Phạm Duy Trung

• Ngoại lệ trong Java là đối tượng, đều là hậu duệ của lớp Throwable • Trình biên dịch chỉ quan tâm đến các ngoại lệ được kiểm tra (checked exception) • Không bắt buộc phải xử lý các ngoại lệ kiểu unchecked • Đăng ký ngoại lệ khi khai báo phương thức sử dụng throws • Chủ động ném ngoại lệ sử dụng từ khóa throw • Sử dụng try/catch/finally để xử lý ngoại lệ, nếu không xử lý được thì đăng ký ngoại lệ để né, chuyển ngoại lệ cho cấp hàm cao hơn xử lý

pdf50 trang | Chia sẻ: huongthu9 | Lượt xem: 401 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu Giáo trình Kỹ thuật phần mềm - Chương 4: Xử lý ngoại lệ - Phạm Duy Trung, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Exception handling XỬ LÝ NGOẠI LỆ PHẠM DUY TRUNG Bộ môn Kỹ thuật Phần mềm Nhắc lại bài cũ • Class và object • 4 chữ P : public, protected, package, private • static và non-static • Bao gói dữ liệu • Kế thừa • Lớp và phương thức trừu tượng • Đa hình: nạp chồng và ghi đè phương thức duytrung.tcu@gmail.com Nội dung bài học Tiếp cận với ngoại lệ Cây ngoại lệ trong java Cơ chế xử lý ngoại lệ trong java Các thao tác xử lý ngoại lệ trong java Ngoại lệ người dùng tự định nghĩa duytrung.tcu@gmail.com Nội dung bài học Tiếp cận với ngoại lệ Cây ngoại lệ trong java Cơ chế xử lý ngoại lệ trong java Các thao tác xử lý ngoại lệ trong java Ngoại lệ người dùng tự định nghĩa duytrung.tcu@gmail.com Đặt vấn đề • Khi viết một chương trình nói chung, lỗi có thể xảy ra với rất nhiều lý do  Người lập trình: sử dụng đệ quy không hợp lý  Người dùng nhập vào dữ liệu không hợp lệ  Nguyên nhân phần cứng, hệ điều hành • Lỗi xảy ra rất đa dạng, khiến chương trình kết thúc đột ngột, cần nâng cao khả năng chịu lỗi của chương trình:  Cho phép người dùng quay lại trạng thái an toàn trước đó để thực hiện các công việc khác  Ghi lại dữ liệu hiện thời rồi mới kết thúc chương trình duytrung.tcu@gmail.com Xử lý thế nào khi gặp lỗi? • Yêu cầu: viết hàm để đọc vào nội dung của một file? readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } duytrung.tcu@gmail.com Xử lý thế nào khi gặp lỗi? • Để giải quyết các tình huống đã nêu, hàm readFile cần có thêm các đoạn code để phát hiện, thông báo và xử lý lỗi duytrung.tcu@gmail.com errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode and -4; } } else { errorCode = -5; } return errorCode; } Xử lý thế nào khi gặp lỗi? duytrung.tcu@gmail.com errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode and -4; } } else { errorCode = -5; } return errorCode; } Code phình ra, bố cục rắc rối, tính đọc hiểu kém Mất cấu trúc logic, khó kiểm soát hành vi của chương trình Khó khăn khi bảo trì, chỉnh sửa code chương trình Xử lý thế nào khi gặp lỗi? • Cần tách biệt phần logic của chương trình với xử lý lỗi duytrung.tcu@gmail.com readFile { try { open the file; determine the length of the file; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } } Nội dung bài học Tiếp cận với ngoại lệ Cây ngoại lệ trong java Cơ chế xử lý ngoại lệ trong java Các thao tác xử lý ngoại lệ trong java Ngoại lệ người dùng tự định nghĩa duytrung.tcu@gmail.com Tiếp cận với ngoại lệ • Ý tưởng: xây dựng nên các đối tượng đặc trưng cho những bất thường xảy ra khi thực thi chương trình • Tìm cách khái quát hóa, phân loại và nhóm các bất thường tương tự với nhau lại -> Keyword: Exception ~ ngoại lệ hay biệt lệ • Trong Java, lớp cao nhất xử lý lỗi là lớp Throwable, với 2 lớp con là Error và Exception • Trong Java, ngoại lệ được “ném” ra bởi các phương thức duytrung.tcu@gmail.com Các lớp ngoại lệ trong Java duytrung.tcu@gmail.com Mô tả các lỗi hệ thống, rất hiếm khi xảy ra như lỗi JVM, lỗi tràn bộ đệm Người dùng gần như không thể làm gì hơn khi những lỗi này xảy ra và chương trình sẽ kết thúc bởi Java runtime Mô tả các lỗi thuộc về chương trình của người dùng. Những lỗi này có thể được “bắt” lại và xử lý. Ví dụ 1 duytrung.tcu@gmail.com Ví dụ 2 duytrung.tcu@gmail.com Cấu trúc tên ngoại lệ trong Java duytrung.tcu@gmail.com + Exception IOException FileNotFoundException ArithmeticException ArrayIndexOutOfBoundsException NullPointerException IllegalArgumentException + Error StackOverflowError JVMError NoClassDefFoundError LinkageError AssertionError Nội dung bài học Tiếp cận với ngoại lệ Cây ngoại lệ trong java Cơ chế xử lý ngoại lệ trong java Các thao tác xử lý ngoại lệ trong java Ngoại lệ người dùng tự định nghĩa duytrung.tcu@gmail.com Ngăn xếp gọi hàm – Method call stack 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()"); } duytrung.tcu@gmail.com 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() Truy vết gọi hàm – call stack trace duytrung.tcu@gmail.com public static void methodC() { System.out.println("Enter methodC()"); System.out.println(1 / 0); System.out.println("Exit methodC()"); } ArithmeticException / by zero 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 Một số phương thức thường dùng 1 public String getMessage() Trả về thông báo lỗi của đối tượng ngoại lệ hiện tại. Thông báo này được truyền qua hàm khởi tạo kiểu Throwable 2 public Throwable getCause() Trả về nguyên nhân gây ra ngoại lệ bằng một đối tượng kiểu Throwable 3 public String toString() Trả về tên của ngoại lệ kèm thông báo lỗi 4 public void printStackTrace() In ra truy vết trên ngăn xếp gọi hàm 5 public StackTraceElement [] getStackTrace() Trả về mảng chứa các phần tử truy vết của ngăn xếp gọi hàm. Phần tử có chỉ số bằng 0 thể hiện đỉnh ngắn xếp, phần từ cuối cùng thể hiện đáy ngăn xếp duytrung.tcu@gmail.com Throwable(): Khởi tạo một đối tượng mới với thông báo lỗi mặc định bằng null Throwable(String message): Khởi tạo một đối tượng mới và truyền vào thông báo lỗi Throwable(Stringmessage, Throwable cause):Khởi tạo một đối tượng mới, truyền vào thông báo lỗi và nguyên nhân Cơ chế xử lý ngoại lệ của Java duytrung.tcu@gmail.com • Khi xảy ra bất thường trong một phương thức Java, nó sẽ tạo ra một đối tượng Exception và gửi đến JVM -> “ném” (throw) ra môt ngoại lệ • JVM sẽ dò ngược từ đỉnh stack nhằm tìm ra “trình xử lý” ngoại lệ phù hợp -> “bắt” (catch) lấy ngoại lệ • Nếu không tìm được, JVM sẽ kết thúc chương trình ngay lập tức Phân loại ngoại lệ Unchecked Exception Checked Exception • Chỉ được xác định khi chạy chương trình (Runtime exceptions) • Không được kiểm tra bởi trình biên dịch -> Không yêu cầu phải “bắt” lỗi hay “ném” lỗi • Thường là các bug như lỗi logic hay sử dụng API không đúng cách, hay các lỗi hệ thống • Gồm lớp con RuntimeException và lớp Error • Được kiểm tra trong khi biên dịch chương trình (Compile time exceptions) • Bắt buộc phải có cách xử lý, hoặc khai báo “ném” ngoại lệ đi tiếp, nếu không sẽ báo lỗi • Là các ngoại lệ có thể dự báo và khắc phục từ khi viết chương trình • Là tất cả các lớp ngoại lệ còn lại duytrung.tcu@gmail.com Phân loại ngoại lệ duytrung.tcu@gmail.com Xác định kiểu ngoại lệ • Ta gọi đến một phương thức ở một lớp mà ta không viết • Làm thế nào để biết một phương thức có thể “ném” ngoại lệ hay không? và “ném” những ngoại lệ nào? -> tìm đến dòng khai báo phương thức, ở đó sẽ khai báo các ngoại lệ -> đọc tài liệu đặc tả phương thức duytrung.tcu@gmail.com Xác định kiểu ngoại lệ duytrung.tcu@gmail.com Nội dung bài học Tiếp cận với ngoại lệ Cây ngoại lệ trong java Cơ chế xử lý ngoại lệ trong java Các thao tác xử lý ngoại lệ trong java Ngoại lệ người dùng tự định nghĩa duytrung.tcu@gmail.com Các thao tác xử lý ngoại lệ trong Java • Xử lý ngoại lệ trong Java sử dụng 3 thao tác sau: 1. Đăng ký ngoại lệ cho phương thức 2. “Ném” ngoại lệ 3. “Bắt” ngoại lệ 5 từ khóa được sử dụng trong xử lý ngoại lệ: try, catch, finally, throws và throw duytrung.tcu@gmail.com Đăng ký ngoại lệ và từ khóa “throws” • Khi khai báo một phương thức Java, cần phải khai báo rõ các ngoại lệ mà phương thức có thể “ném” ra bằng từ khóa “throws” public void methodD() throws XxxException, YyyException { // method body throw XxxException and YyyException } -> methodD có thể phát sinh 2 ngoại lệ kiểu checked là XxxException và YyyException • Các ngoại lệ unchecked thì không cần khai báo duytrung.tcu@gmail.com “Ném” ngoại lệ và từ khóa “throw” • Trong phần thân hàm, khi gặp những điều kiện hay đoạn lệnh tiềm ẩn lỗi, xây dựng một đối tượng ngoại lệ phù hợp và chuyển cho JVM bằng từ khóa “throw” 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 ... } duytrung.tcu@gmail.com “Ném” ngoại lệ và từ khóa “throw” • Trong phần thân hàm, khi gặp những điều kiện hay đoạn lệnh tiềm ẩn lỗi, xây dựng một đối tượng ngoại lệ phù hợp và chuyển cho JVM bằng từ khóa “throw” 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 ... } duytrung.tcu@gmail.com “Ném” ngoại lệ và từ khóa “throw” public class Test { public static void main(String[] args) { tinhCanBacHai(-6); } static double tinhCanBacHai(double x) { if(x<0) throw new ArithmeticException("Không thể lấy căn số âm"); return Math.sqrt(x); } } duytrung.tcu@gmail.com “Bắt” ngoại lệ - Nguyên tắc “Bắt hoặc Né“ • Nguyên gốc theo tài liệu Oracle: Catch or Specify Requirement • Khi một đoạn code trong một phương thức phát sinh ngoại lệ, phương thức có thể xử lý theo một trong hai cách sau: 1. Bắt: Đưa code vào trong một khối try/catch và cung cấp trình xử lý ngoại lệ phù hợp với mỗi ngoại lệ 2. Né: Chỉ rõ ngoại lệ mà phương thức hiện tại sẽ ném ra tương tự như khai báo ngoại lệ bằng từ khóa throws, chứ không xử lý nó. Khi phát sinh ngoại lệ, JVM sẽ kết thúc phương thức hiện tại và chuyển ngoại lệ cấp cao hơn trong ngăn xếp gọi hàm. Hàm khởi tạo kiểu có đối số duytrung.tcu@gmail.com “Bắt” ngoại lệ - Nguyên tắc “Bắt hoặc Né“ duytrung.tcu@gmail.com “Bắt” ngoại lệ - Nguyên lý “Bắt hoặc Né” duytrung.tcu@gmail.com “Bắt” ngoại lệ - Nguyên lý “Bắt hoặc Né” duytrung.tcu@gmail.com 1 2 Khối try / catch • Để xử lý ngoại lệ được ném ra từ một đoạn mã, ta bọc đoạn mã đó trong một khối try / catch • Khối try chứa phần mã có thể phát sinh ngoại lệ • Khối catch chứa đoạn mã xử lý ngoại lệ (exception handler) trong trường hợp khối try phát sinh ngoại lệ • Cấu trúc try / catch chỉ có một khối try song có thể có nhiều hơn một khối catch để xử lý nhiều lớp ngoại lệ khác nhau duytrung.tcu@gmail.com Hoạt động của khối try/catch Trường hợp 1: Khi phương thức/ đoạn mã trong try thực hiện thành công, khối lệnh trong catch bị bỏ qua, lệnh đằng sau catch sẽ chạy duytrung.tcu@gmail.com Hoạt động của khối try / catch duytrung.tcu@gmail.com Khi phương thức/ đoạn mã trong try ném ra ngoại lệ và khối catch bắt được ngoại lệ đó. - Các lệnh còn lại trong khối try bị bỏ qua - Khối catch được thực hiện - Các lệnh sau khối catch được thực hiện Hoạt động của khối try / catch duytrung.tcu@gmail.com Khi phương thức/ đoạn mã trong try ném ra ngoại lệ mà khối catch không bắt được - Bỏ qua các lệnh còn lại trong phương thức - Trở về phương thức gọi đến phương thức hiện tại tìm trình xử lý hoặc dừng chương trình ra khỏi phương thức hiện tại Sử dụng nhiều catch duytrung.tcu@gmail.com Thứ tự các khối catch • Ngoại lệ cũng là đối tượng nên có tính đa hình: một khối catch bắt được ngoại lệ lớp cha thì cũng bắt được ngoại lệ lớp con • Khối catch dành cho ngoại lệ tổng quát hơn phải đặt sau khối catch cho ngoại lệ chuyên biệt hơn, nếu không Java sẽ báo lỗi duytrung.tcu@gmail.com public class FileNotFound_Demo { public static void main(String[] args){ File file = new File("E:\\file.txt"); try { FileReader fr = new FileReader(file); } catch (FileNotFoundException ex) { System.out.println("File không tồn tại"); } catch (IOException ex) { System.out.println("Có lỗi vào / ra"); } catch (Exception ex) { System.out.println("Có lỗi gì đó :("); } } } Throwable Exception IOException FileNotFoundException Error Khối finally – những việc thế nào cũng phải làm • Là khối tùy chọn, thêm vào khối try / catch • Để thêm những công việc phải làm bất kể ngoại lệ có xảy ra hay không, kể cả khi trong try catch có từ khóa return • Một cách dùng phổ biến là chứa code làm nhiệm vụ “dọn dẹp”: đóng file, đóng stream duytrung.tcu@gmail.com import java.io.File; import java.io.FileReader; import java.io.IOException; public class ReadData_Demo { public static void main(String args[]) { FileReader fr = null; try { File file = new File("file.txt"); fr = new FileReader(file); char [] a = new char[50]; fr.read(a); // reads the content to the array for(char c : a) System.out.print(c); // prints the characters one by one } catch (IOException e) { e.printStackTrace(); }finally { try { fr.close(); } catch (IOException ex) { ex.printStackTrace(); } } } } Ví dụ try/catch/finally duytrung.tcu@gmail.com Đã mở file thì phải đóng file lại, bất kể chạy được hay phát sinh ngoại lệ Sử dụng try-with-resources • Là cơ chế xử lý exception xuất hiện từ Java SE 7 • “Tài nguyên” (resource) là một đối tượng mà phải được đóng lại sau khi thao tác xong • Chỉ cần đối tượng thực thi interface java.lang.AutoCloseable, thì có thể sử dụng câu lệnh try-with-resource • Tài nguyên đươc khai báo ở câu lệnh try sẽ tự động đóng lại bất kể khối lệnh của try chạy bình thường hay gặp lỗi -> không cần khối finally để dọn dẹp trong trường hợp này duytrung.tcu@gmail.com Ví dụ try-with-resources duytrung.tcu@gmail.com import java.io.FileReader; import java.io.IOException; public class Try_withDemo { public static void main(String args[]) { try(FileReader fr = new FileReader("E://file.txt")) { char [] a = new char[50]; fr.read(a); // reads the contentto the array for(char c : a) System.out.print(c); // prints the characters one by one } catch (IOException e) { e.printStackTrace(); } } } Nội dung bài học Tiếp cận với ngoại lệ Cây ngoại lệ trong java Cơ chế xử lý ngoại lệ trong java Các thao tác xử lý ngoại lệ trong java Ngoại lệ người dùng tự định nghĩa duytrung.tcu@gmail.com Ngoại lệ người dùng định nghĩa • Yêu cầu của chương trình nhiều khi đòi hỏi người lập trình phải định nghĩa thêm các ngoại lệ mới • Để sử dụng được với cơ chế ngoại lệ thông thường, ngoại lệ tự định nghĩa cần kế thừa và chuyên biệt hóa các lớp ngoại lệ có sẵn trong Java -> đều là hậu duệ của lớp Throwable • Để viết một ngoại lệ kiểu checked, chỉ cần kế thừa lớp Exception • Để viết một ngoại lệ kiểu unchecked, phải kế thừa lớp RuntimeException duytrung.tcu@gmail.com Ngoại lệ người dùng định nghĩa duytrung.tcu@gmail.com public class Test { public static void main(String[] args) throws MyException { int a = 5; if(a>0) { MyException ex = new MyException("Có lỗi gì đó"); System.out.println(ex.getNotiStr()); throw ex; } } } class MyException extends Exception { private String notiStr = "Một dòng thông báo bình thường"; public MyException() { super("Đây là ngoại lệ của tôi"); } public MyException(String mess){ super("Đây là ngoại lệ của tôi"); notiStr = mess; } public String getNotiStr() { return notiStr; } } Kinh nghiệm sử dụng • Một ngoại lệ tự định nghĩa điển hình chỉ cần đưa ra 2 hàm khởi tạo, một không có đối số và một có đối số truyền vào là thông báo lỗi tùy chọn • Trong nhiều trường hợp chỉ cần một lớp con rỗng với tên lớp phù hợp là đủ • Khi kế thừa ngoại lệ, nên chọn lớp cha là một lớp có liên quan • Việc sử dụng ngoại lệ tự định nghĩa giúp tăng tính trong sáng của chương trình, tăng tính đọc hiểu của code duytrung.tcu@gmail.com Tổng kết bài học • Ngoại lệ trong Java là đối tượng, đều là hậu duệ của lớp Throwable • Trình biên dịch chỉ quan tâm đến các ngoại lệ được kiểm tra (checked exception) • Không bắt buộc phải xử lý các ngoại lệ kiểu unchecked • Đăng ký ngoại lệ khi khai báo phương thức sử dụng throws • Chủ động ném ngoại lệ sử dụng từ khóa throw • Sử dụng try/catch/finally để xử lý ngoại lệ, nếu không xử lý được thì đăng ký ngoại lệ để né, chuyển ngoại lệ cho cấp hàm cao hơn xử lý duytrung.tcu@gmail.com Bài tập về nhà Viết một chương trình minh họa việc rút tiền tại cây ATM - Tạo một lớp mô tả một tài khoản ngân hàng với thuộc tính số dư tài khoản ($) và 2 phương thức nạp tiền và rút tiền - Khi gọi phương thức nạp tiền và rút tiền, để người dùng nhập vào số tiền cần rút/nạp, chi phí rút/nạp bằng 1% số tiền. Hãy xử lý các ngoại lệ có thể phát sinh - Tự định nghĩa các ngoại lệ để bắt các tính huống sau: • Số tiền nhập vào là số âm • Số tiền nhập vào lớn hơn số dư tài khoản • Số tiền cần rút lớn hơn 300$/giao dịch duytrung.tcu@gmail.com

Các file đính kèm theo tài liệu này:

  • pdfbai_giang_ky_thuat_phan_mem_chuong_4_pham_duy_trung_4587_207.pdf