Bài giảng Lập trình hướng đối tượng - Bài 8: Ngoại lệ và xử lý ngoại lệ

9/18/17  
Mục tiêu của bài học  
n Giải thích về ngoại lệ là gì và mô tả các lợi  
Bộ môn Công nghệ Phần mềm  
Viện CNTT & TT  
ích của việc xử lý ngoại lệ hướng đối tượng  
Trường Đại học Bách Khoa Hà Nội  
n Giải thích được mô hình xử lý ngoại lệ  
n Sử dụng khối try/catch/finally để bắt và xử lý  
ngoại lệ trong Java  
LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG  
n Hiểu và biết cách sử dụng ủy nhiệm ngoại lệ  
Bài 08. Ngoại lệ và xử lý ngoại lệ  
n Biết cách tạo ra và sử dụng ngoại lệ tự định  
nghĩa  
2
Nội dung  
Nội dung  
1. Ngoại lệ  
1. Ngoại lệ  
2. Bắt và xử lý ngoại lệ  
3. Ủy nhiệm ngoại lệ  
4. Tạo ngoại lệ tự định nghĩa  
2. Bắt và xử lý ngoại lệ  
3. Ủy nhiệm ngoại lệ  
4. Tạo ngoại lệ tự định nghĩa  
3
4
1
9/18/17  
1.1. Ngoại lệ là gì?  
1.1. Ngoại lệ là gì? (2)  
n Exception = Exceptional event  
n Ngoại lệ là một lỗi đặc biệt  
n Định nghĩa: Ngoại lệ là một sự kiện xảy ra  
trong quá trình thực thi chương trình, nó phá  
vỡ luồng bình thường của chương trình  
n Khi xảy ra một ngoại lệ, nếu không xử lý thì  
chương trình kết thúc ngay và trả lại quyền  
điều khiển cho hệ điều hành.  
ERROR !!  
Ví dụ:  
5
6
1.2. Cách xử lý lỗi truyền thống  
Ví dụ  
int devide(int num, int denom, int *error)  
n Viết mã xử lý tại nơi phát sinh ra lỗi  
{
n
Làm cho chương trình trở nên rối  
if (denom != 0){  
error = 0;  
return num/denom;  
} else {  
n
Không phải lúc nào cũng đầy đủ thông tin để xử  
lý  
n
Không nhất thiết phải xử lý  
n Truyền trạng thái lên mức trên  
error = 1;  
return 0;  
}
n
Thông qua tham số, giá trị trả lại hoặc biến tổng  
thể (flag)  
}
n
n
Dễ nhầm  
Vẫn còn khó hiểu  
7
8
2
9/18/17  
Nhược điểm  
Nội dung  
n Khó kiểm soát được hết các trường hợp  
1. Ngoại lệ  
n
Lỗi số học, lỗi bộ nhớ,…  
2. Bắt và xử lý ngoại lệ  
3. Ủy nhiệm ngoại lệ  
n Lập trình viên thường quên không xử lý lỗi  
n
n
Bản chất con người  
4. Tạo ngoại lệ tự định nghĩa  
Thiếu kinh nghiệm, cố tình bỏ qua  
9
10  
2.1. Mục đích của xử lý ngoại lệ  
2.1. Mục đích của xử lý ngoại lệ (2)  
n Giúp chương trình đáng tin cậy hơn, tránh  
n Khi xảy ra ngoại lệ, nếu không có cơ chế xử  
kết thúc bất thường  
lý thích hợp:  
n Tách biệt khối lệnh có thể gây ngoại lệ và  
n
Chương trình bị ngắt khi ngoại lệ xảy ra  
khối lệnh xử lý ngoại lệ  
…………  
n
Các tài nguyên không được giải phóng à Lãng  
IF B IS ZERO GO TO ERROR  
C = A/B  
phí  
PRINT C  
GO TO EXIT  
n Ví dụ: Vào/ra tệp tin  
n
Nếu ngoại lệ xảy ra (ví dụ như chuyển đổi kiểu  
không đúng) à Chương trình kết thúc mà không  
ERROR:  
DISPLAY “DIVISION BY ZERO”  
Khối xử lý lỗi  
đóng tệp tin lại  
EXIT:  
END  
n
Tệp tin không thể truy cập/hỏng  
11  
12  
n
Tài nguyên cấp phát không được giải phóng  
3
9/18/17  
2.2. Mô hình xử lý ngoại lệ  
2.2. Mô hình xử lý ngoại lệ (2)  
n Hướng đối tượng  
n Ngoại lệ cần phải được xử lý ở tại phương  
thức sinh ra ngoại lệ hoặc ủy nhiệm cho  
phương thức gọi đến  
n
Đóng gói các điều kiện không mong đợi trong một đối  
tượng  
n
Khi xảy ra ngoại lệ, đối tượng tương ứng với ngoại lệ  
được tạo ra chứa thông tin chi tiết về ngoại lệ  
n
n
Cung cấp cơ chế hiệu quả trong việc xử lý lỗi  
Tách biệt luồng điều khiển bất thường với luồng bình  
thường  
13  
14  
2.3. Xử lý ngoại lệ trong Java  
2.3. Xử lý ngoại lệ trong Java (2)  
n Java có cơ chế xử lý ngoại lệ rất  
n Các từ khóa  
mạnh  
n
n
n
n
n
try  
n Xử lý ngoại lệ trong Java được  
thực hiện theo mô hình hướng đối  
tượng:  
catch  
finally  
throw  
n
Tất cả các ngoại lệ đều là thể hiện  
của một lớp kế thừa từ lớp Throwable  
hoặc các lớp con của nó  
throws  
n
Các đối tượng này có nhiệm vụ  
chuyển thông tin về ngoại lệ (loại và  
trạng thái của chương trình) từ vị trí  
xảy ra ngoại lệ đến nơi quản lý/xử lý  
nó.  
16  
4
9/18/17  
Ví dụ không xử lý ngoại lệ  
2.3.1. Khối try/catch  
class NoException {  
n Khối try ... catch: Phân tách đoạn chương  
public static void main(String args[]) {  
String text = args[0];  
System.out.println(text);  
}
trình thông thường và phần xử lý ngoại lệ  
n
try {…}: Khối lệnh có khả năng gây ra ngoại lệ  
n
catch() {…}: Bắt và xử lý với ngoại lệ  
try {  
// Doan ma co the gay ngoai le  
}
}
catch (ExceptionType e) {  
// Xu ly ngoai le  
}
17  
18  
n ExceptionTypelà một lớp con của Throwable  
Ví dụ có xử lý ngoại lệ  
Ví dụ chia cho 0  
public class ChiaCho0Demo {  
public static void main(String args[]){  
try {  
class ArgExceptionDemo {  
public static void main(String args[]) {  
try {  
int num = calculate(9,0);  
System.out.println(num);  
}
catch(Exception e) {  
System.err.println("Co loi xay ra: " + e.toString());  
String text = args[0];  
System.out.println(text);  
}
catch(Exception e) {  
}
System.out.println(“Hay nhap tham so khi chay!");  
}
}
static int calculate(int no, int no1){  
}
int num = no / no1;  
return num;  
}
}
}
19  
20  
5
9/18/17  
a. Lớp Throwable  
2.3.2. Cây phân cấp ngoại lệ trong Java  
n
n
Một biến kiểu String để lưu thông tin chi tiết về  
ngoại lệ đã xảy ra  
Một số phương thức cơ bản  
Error chỉ ra các lỗi đặc  
biệt nghiêm trọng, những  
lỗi này chương trình  
không thể quản lý được.  
VD: VirtualMachineError  
OutOfMemoryError  
Thro
Exception là lớp cơ sở  
cho tất cả các lỗi có thể  
ect  
kiểm soát được.  
n
new Throwable(String s):Tạo một ngoại lệ với  
VD: ArithmeticException,  
BufferOverflowException  
Throwable  
thông tin về ngoại lệ là s  
n
n
n
String getMessage():Lấy thông tin về ngoại lệ  
String getString():Mô tả ngắn gọn về ngoại lệ  
void printStackTrace():In ra tất cả các thông tin  
liên quan đến ngoại lệ (tên, loại, vị trí...)  
…
Error  
...  
Exception  
RuntimeException  
...  
n
...  
21  
22  
b. Lớp Error  
public class StckExceptionDemo {  
public static void main(String args[]){  
try {  
n
n
Gồm các ngoại lệ nghiêm trọng không thể kiểm tra  
(unchecked exception) vì có thể xảy ra ở nhiều phần của  
chương trình.  
Còn gọi là ngoại lệ không thể phục hồi (un-recoverable  
exception)  
int num = calculate(9,0);  
System.out.println(num);  
}
catch(Exception e) {  
System.err.println(“Co loi xay ra :"  
+ e.getMessage());  
e.printStackTrace();  
n
n
Không cần kiểm tra trong mã nguồn Java của bạn  
Các lớp con:  
}
n
VirtualMachineError: InternalError, OutOfMemoryError,  
}
StackOverflowError, UnknownError  
static int calculate(int no, int no1)  
{
n
n
ThreadDeath  
LinkageError:  
int num = no / no1;  
return num;  
}
n
IncompatibleClassChangeError  
n
AbstractMethodError, InstantiationError, NoSuchFieldError,  
NoSuchMethodError…  
}
n
…
n
…
23  
24  
6
9/18/17  
c. Lớp Exception  
Một số lớp con của Exception  
n Chứa các loại ngoại lệ  
n ClassNotFoundException, SQLException  
n java.io.IOException:  
nên/phải bắt và xử lý hoặc ủy  
nhiệm.  
n
FileNotFoundException, EOFException…  
n Người dùng có thể tạo ra các  
ngoại lệ của riêng mình bằng  
cách kế thừa từ Exception  
n RuntimeException:  
n
n
n
NullPointerException, BufferOverflowException  
ClassCastException, ArithmeticException  
IndexOutOfBoundsException:  
n RuntimeException có thể  
được “tung” ra trong quá  
trình JVM thực hiện  
n
ArrayIndexOutOfBoundsException,  
StringIndexOutOfBoundsException…  
n
n
Không bắt buộc phải bắt ngoại  
lệ dù có thể xảy ra lỗi  
n
n
IllegalArgumentException:  
n
NumberFormatException, InvalidParameterException…  
n
Không nên viết ngoại lệ của  
riêng mình kế thừa từ lớp này  
…
25  
26  
Ví dụ IOException  
2.3.3. Khối try – catch lồng nhau  
import java.io.InputStreamReader;  
n Những phần nhỏ trong khối mã sinh ra một lỗi,  
nhưng toàn bộ cả khối thì lại sinh ra một lỗi  
khác à Cần có các xử lý ngoại lệ lồng nhau.  
import java.io.IOException;  
public class HelloWorld{  
public static void main(String[] args) {  
n Khi các khối try lồng nhau, khối try bên trong sẽ  
InputStreamReader isr = new  
InputStreamReader(System.in);  
được thực hiện trước.  
try {  
try {  
System.out.print("Nhap vao 1 ky tu: ");  
// Doan ma co the gay ra IOException  
try {  
char c = (char) isr.read();  
// Doan ma co the gay ra NumberFormatException }  
System.out.println("Ky tu vua nhap: " + c);  
catch (NumberFormatException e1) {  
}catch(IOException ioe) {  
// Xu ly loi sai dinh dang so  
}
ioe.printStackTrace();  
} catch (IOException e2) {  
// Xu ly loi vao ra  
}
}
}
}
28  
7
9/18/17  
2.3.4. Nhiều khối catch  
ExceptionType1 phải là lớp con hoặc ngang hàng v  
n ới ExceptionType2 (trong cây phân cấp kế thừa)  
class MultipleCatch1 {  
public static void main(String args[])  
{
n Một đoạn mã có thể gây ra nhiều hơn một ngoại lệ à  
Sử dụng nhiều khối catch.  
try {  
try {  
// Doan ma co the gay ra nhieu ngoai le  
} catch (ExceptionType1 e1) {  
// Xu ly ngoai le 1  
} catch (ExceptionType2 e2) {  
// Xu ly ngoai le 2  
} ...  
String num = args[0];  
int numValue = Integer.parseInt(num);  
System.out.println("Dien tich hv la: "  
+ numValue * numValue);  
} catch(Exception e1) {  
System.out.println("Hay nhap canh cua hv!");  
} catch(NumberFormatException e2){  
System.out.println("Not a number!");  
}
n ExceptionType1 phải là lớp con hoặc ngang hàng với  
}
ExceptionType2 (trong cây phân cấp kế thừa)  
D:\exception java.lang.NumberFormatException has already been  
caught  
}
Lỗi  
29  
30  
class MultiCatch2 {  
n ExceptionType1 phải là lớp con hoặc ngang  
hàng với ExceptionType2 (trong cây phân cấ  
p kế thừa)  
class MultipleCatch1 {  
public static void main(String args[])  
{
public static void main( String args[]) {  
try {  
// format a number  
// read a file  
// something else...  
}
catch(IOException e) {  
try {  
String num = args[0];  
System.out.println("I/O error "+e.getMessage();  
int numValue = Integer.parseInt(num);  
System.out.println("Dien tich hv la: "  
+ numValue * numValue);  
} catch(ArrayIndexOutOfBoundsException e1) {  
System.out.println(“Hay nhap canh cua hv!");  
} catch(NumberFormatException e2){  
System.out.println(“Hay nhap 1 so!");  
}
}
catch(NumberFormatException e) {  
System.out.println("Bad data "+e.getMessage();  
}
catch(Throwable e) { // catch all  
System.out.println("error: " + e.getMessage();}  
}
}
}
}
31  
32  
}
8
9/18/17  
...  
2.3.5. Khối finally  
public void openFile(){  
try {  
// constructor may throw FileNotFoundException  
FileReader reader = new FileReader("someFile");  
int i=0;  
while(i != -1) {  
n Đảm bảo thực hiện tất cả các công việc cần  
thiết khi có ngoại lệ xảy ra  
//reader.read() may throw IOException  
i = reader.read();  
n
Đóng file, đóng socket, connection  
n
Giải phóng tài nguyên (nếu cần)...  
System.out.println((char) i );  
}
n Chắc chắn sẽ thực hiện dù ngoại lệ có xảy ra  
reader.close();  
System.out.println("--- File End ---");  
hay không.  
} catch (FileNotFoundException e) {  
No exception  
finally  
//do something clever with the exception  
} catch (IOException e) {  
//do something clever with the exception  
try block  
}
}
...  
catch block  
finally  
Exception  
33  
34  
class StrExceptionDemo  
static String str;  
public static void main(String s[])  
try {  
{
Cú pháp try ... catch ... finally  
{
try {  
System.out.println(“Truoc ngoai le");  
staticLengthmethod();  
System.out.println(“Sau ngoai le");  
// Khoi lenh co the sinh ngoai le  
}
catch(ExceptionType e) {  
}
// Bat va xu ly ngoai le  
catch(NullPointerException ne)  
{
System.out.println(“Da xay ra loi");  
}
}
finally {  
finally {  
/* Thuc hien cac cong viec can thiet du  
System.out.println(“Trong finally");  
ngoai le co xay ra hay khong */  
}
}
}
n
Nếu đã có khối try thì bắt buộc phải có khối  
catch hoặc khối finally hoặc cả hai  
static void staticLengthmethod() {  
System.out.println(str.length());  
}
}
35  
36  
9
9/18/17  
public void openFile(){  
Nội dung  
try {  
// constructor may throw FileNotFoundException  
FileReader reader = new FileReader("someFile");  
int i=0;  
while(i != -1) {  
1. Ngoại lệ  
//reader.read() may throw IOException  
i = reader.read();  
System.out.println((char) i );  
}
} catch (FileNotFoundException e) {  
//do something clever with the exception  
} catch (IOException e) {  
//do something clever with the exception  
} finally {  
2. Bắt và xử lý ngoại lệ  
3. Ủy nhiệm ngoại lệ  
4. Tạo ngoại lệ tự định nghĩa  
reader.close();  
System.out.println("--- File End ---");  
}
}
37  
38  
3.1. Ủy nhiệm ngoại lệ  
Hai cách làm việc với ngoại lệ  
n
Phương thức có thể ủy nhiệm ngoại lệ cho vị trí gọi nó bằ  
ng cách:  
n Xử lý ngay  
n
Sử dụng khối try ... catch (finally nếu cần).  
n
Sử dụng throws ExceptionType ở phần khai báo phương thức  
để báo hiệu cho vị trí gọi nó biết là nó có thể phát sinh ngoại l  
ệ ExceptionType  
n Ủy nhiệm cho vị trí gọi nó:  
n
Nếu không muốn xử lý ngay  
n
Sử dụng throw để tung ra ngoại lệ kiểu ExceptionType trong  
thân phương thức khi cần  
n
Sử dụng throw và throws  
n
Ví dụ  
public void myMethod(int param) throws Exception{  
if (param < 10) {  
throw new Exception("Too low!");  
}
//Blah, Blah, Blah...  
}
39  
40  
10  
9/18/17  
3.1. Ủy nhiệm ngoại lệ (2)  
3.1. Ủy nhiệm ngoại lệ (3)  
n
n
Phương thức không cần phải khai báo sẽ tung ra  
RuntimeException vì ngoại lệ này mặc định được ủy  
nhiệm cho JVM  
Ví dụ  
class Test {  
public void myMethod(int param) {  
if (param < 10) {  
n Nếu phương thức có chứa câu lệnh tung ngo  
ại lệ (throw) thì phần khai báo phương thức  
phải khai báo là có tung ngoại lệ đó hoặc lớp  
cha của ngoại lệ đó  
public void myMethod(int param) {  
if (param < 10) {  
throw new RuntimeException("Too low!");  
throw new Exception("Too low!");  
}
}
//Blah, Blah, Blah...  
//Blah, Blah, Blah...  
}
}
}
n
à Không lỗi  
à unreported exception java.lang.Exception; must be  
caught or declared to be thrown  
41  
42  
3.1. Ủy nhiệm ngoại lệ (3)  
public class DelegateExceptionDemo {  
public static void main(String args[]){  
int num = calculate(9,3);  
System.out.println(“Lan 1: ” + num);  
num = calculate(9,0);  
n Tại vị trí gọi phương thức có ủy nhiệm ngoại  
System.out.println(“Lan 2: ” + num);  
}
static int calculate(int no, int no1)  
throws ArithmeticException {  
if (no1 == 0)  
lệ (trừ RuntimeException):  
n
Hoặc là phương thức chứa vị trí đó phải ủy nhiệ  
m tiếp cho vị trí gọi mình  
n
Hoặc là tại ví trí gọi phải bắt ngoại lệ ủy nhiệm  
(hoặc lớp cha) và xử lý ngay bằng try...catch  
(finally nếu cần)  
throw new  
ArithmeticException("Khong the chia cho 0!");  
int num = no / no1;  
return num;  
}
}
43  
44  
11  
9/18/17  
public class DelegateExceptionDemo {  
public static void main(String args[]){  
public class DelegateExceptionDemo {  
public static void main(String args[]){  
try {  
int num = calculate(9,3);  
System.out.println(“Lan 1: ” + num);  
num = calculate(9,0);  
int num = calculate(9,3);  
System.out.println(“Lan 1: ” + num);  
num = calculate(9,0);  
System.out.println(“Lan 2: ” + num);  
} catch(Exception e) {  
System.out.println(e.getMessage());  
}
System.out.println(“Lan 2: ” + num);  
}
static int calculate(int no, int no1)  
throws Exception {  
if (no1 == 0)  
throw new  
ArithmeticException("Khong the chia cho 0!");  
int num = no / no1;  
}
static int calculate(int no, int no1)  
throws ArithmeticException {  
if (no1 == 0)  
return num;  
}
}
throw new  
G:\Java Example\DelegateExceptionDemo.java:3: unreported exception java.lang.Exception;  
ArithmeticException("Khong the chia cho 0!");  
int num = no / no1;  
return num;  
must be caught or declared to be thrown  
int num = calculate(9,3);  
^
G:\Java Example\DelegateExceptionDemo.java:5: unreported exception java.lang.Exception;  
must be caught or declared to be thrown  
}
45  
46  
}
num = calculate(9,0);  
3.1. Ủy nhiệm ngoại lệ (4)  
3.2. Lan truyền ngoại lệ  
n Một phương thức có thể ủy nhiệm nhiều hơn  
n Tình huống:  
1 ngoại lệ  
n
Giả sử trong main() gọi phương thức A(), trong  
public void myMethod(int tuoi, String ten)  
throws ArithmeticException, NullPointerException{  
if (tuoi < 18) {  
A() gọi B(), trong B() gọi C(). Khi đó một ngăn  
xếp các phương thức được tạo ra.  
throw new ArithmeticException(“Chua du tuoi!");  
}
n
Giả sử trong C() xảy ra ngoại lệ.  
if (ten == null) {  
throw new NullPointerException(“Thieu ten!");  
}
//Blah, Blah, Blah...  
}
47  
48  
12  
9/18/17  
3.2. Lan truyền ngoại lệ (2)  
3.3. Kế thừa và ủy nhiệm ngoại lệ  
C() tung ngoại lệ  
C()  
n Khi override một phương thức của lớp cha,  
phương thức ở lớp con không được phép  
tung ra các ngoại lệ mới  
B()  
A()  
B()  
A()  
main()  
main()  
n
Nếu C() gặp lỗi và tung ra ngoại lệ nhưng trong C() lại không xử  
lý ngoại lệ này, thì chỉ còn một nơi có thể xử lý chính là nơi mà  
C() được gọi, đó là trong phương thức B().  
n à Phương thức ghi đè trong lớp con chỉ  
được phép tung ra các ngoại lệ giống hoặc là  
lớp con hoặc là tập con của các ngoại lệ đượ  
c tung ra ở lớp cha.  
n
n
Nếu trong B() cũng không xử lý thì phải xử lý ngoại lệ này trong  
A()… Quá trình này gọi là lan truyền ngoại lệ  
Nếu đến main() cũng không xử lý ngoại lệ được tung từ C() thì  
chương trình sẽ phải dừng lại.  
49  
50  
3.3. Kế thừa và ủy nhiệm ngoại lệ (2)  
3.4. Ưu điểm của ủy nhiệm ngoại lệ  
class Disk {  
void readFile() throws EOFException {}  
n Dễ sử dụng  
n
n
n
Làm chương trình dễ đọc và an toàn hơn  
Dễ dàng chuyển điều khiển đến nơi có khả năng xử lý ngoại lệ  
Có thể ném nhiều loại ngoại lệ  
}
class FloppyDisk extends Disk {  
void readFile() throws IOException {} // ERROR!  
}
n Tách xử lý ngoại lệ khỏi đoạn mã thông thường  
n Không bỏ sót ngoại lệ (ném tự động)  
n Gom nhóm và phân loại các ngoại lệ  
class Disk {  
void readFile() throws IOException {}  
}
n KL: Làm chương trình dễ đọc và an toàn  
class FloppyDisk extends Disk {  
hơn  
void readFile() throws EOFException {} //OK  
}
51  
52  
52  
13  
9/18/17  
Nội dung  
4. Tạo ngoại lệ tự định nghĩa  
n Các ngoại lệ do hệ thống xây dựng không đủ  
để kiểm soát tất cả các lỗi à Cần phải có  
các lớp ngoại lệ do người dùng định nghĩa.  
1. Ngoại lệ  
2. Bắt và xử lý ngoại lệ  
n
Kế thừa từ một lớp Exceptionhoặc lớp con của nó  
Có tất cả các phương thức của lớp Throwable  
3. Ủy nhiệm ngoại lệ  
n
public class MyException extends Exception {  
4. Tạo ngoại lệ tự định nghĩa  
public MyException(String msg) {  
super(msg);  
}
public MyException(String msg, Throwable cause){  
super(msg, cause);  
}
}
53  
54  
Sử dụng ngoại lệ người dùng định nghĩa  
Sử dụng ngoại lệ người dùng định nghĩa  
Khai báo khả năng tung ngoại l  
ệ
n Bắt và xử lý ngoại lệ  
public class FileExample  
public class Test {  
{
public static void main(String[] args) {  
public void copyFile(String fName1,String fName2)  
FileExample obj = new FileExample();  
throws MyException  
{
try {  
String a = args[0];  
String b = args[1];  
obj.copyFile(a,b);  
} catch (MyException e1) {  
if (fName1.equals(fName2))  
throw new MyException("File trung ten");  
// Copy file  
System.out.println("Copy completed");  
System.out.println(e1.getMessage());  
}
}
catch(Exception e2) {  
}
System.out.println(e2.toString());  
}
}
}
Tung ngoại lệ  
55  
56  
14  
pdf 14 trang yennguyen 23460 Free
Bạn đang xem tài liệu "Bài giảng Lập trình hướng đối tượng - Bài 8: Ngoại lệ và xử lý ngoại lệ", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

File đính kèm:

  • pdfbai_giang_lap_trinh_huong_doi_tuong_bai_8_ngoai_le_va_xu_ly.pdf