Bài giảng Ngôn ngữ Java - Chương 4: Xử lý ngoại lệ - Phạm Duy Trung

Đặ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.comXử 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;

pdf 50 trang kimcuc 9660
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Ngôn ngữ Java - Chương 4: Xử lý ngoại lệ - Phạm Duy Trung", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Bài giảng Ngôn ngữ Java - Chương 4: Xử lý ngoại lệ - Phạm Duy Trung

Bài giảng Ngôn ngữ Java - Chương 4: Xử lý ngoại lệ - Phạm Duy Trung
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

File đính kèm:

  • pdfbai_giang_ngon_ngu_java_chuong_4_xu_ly_ngoai_le_pham_duy_tru.pdf