Thứ Sáu, 9 tháng 6, 2017

Exception

I.Exception là gì?

Exception là một sự kiện mà phá vỡ luồng chuẩn của chương trình. Nó là một đối tượng mà được ném tại Runtime. Một exception (ngoại lệ) trong Java là một vấn đề xảy ra trong quá trình thực hiện của chương trình. Một ngoại lệ có thể xảy ra với nhiều lý do khác nhau:

Người dùng nhập dữ liệu không hợp lệ.

- Một file cần được mở nhưng không thể tìm thấy.

- Kết nối mạng bị ngắt trong quá trình thực hiện giao tiếp hoặc JVM hết bộ nhớ.


Các loại Exception trong java:

- Checked Exception: Là ngoại lệ thường xảy ra do người dùng mà không thể lường trước được bởi lập trình viên. Ví dụ, một file được mở, nhưng file đó không thể tìm thấy và ngoại lệ xảy ra. Những ngoại lệ này không thể được bỏ qua trong quá trình biên dịch. Checked Exception là các lớp mà kế thừa lớp Throwable ngoại trừ RuntimeException và Error. Ví dụ như IOException, SQLException, … Checked Exception được kiểm tra tại thời gian biên dịch compile-time.

- Unchecked Exception: Một ngoại lệ xảy ra ở runtime là ngoại lệ có thể tránh được bởi lập trình viên. Unchecked Exception là các lớp kế thừa RuntimeException, ví dụ ArithmaticException, NullPointerException, ArrayIndexOutOfBoundsException, … Unchecked Exception không được kiểm tra tại compile-time, thay vào đó chúng được kiểm tra tại runtime.

Error: Nó không giống các exception, nhưng vấn đề xảy ra vượt quá tầm kiểm soát của lập trình viên hay người dùng. Error được bỏ qua trong code của bạn vì bạn hiếm khi có thể làm gì đó khi chương trình bị error. Ví dụ như OutOfMemoryError, VirtualMachineError, AssertionError, … Nó được bỏ qua trong quá trình Java biên dịch.

Xử lý ngoại lệ (Exception Handling) là một kỹ thuật để xử lý các Runtime Error như ClassNotFound, IO, SQL, Remote, … Lợi thế chính của xử lý ngoại lệ là để duy trì luồng chuẩn của ứng dụng. Exception thường phá vỡ luồng chuẩn của ứng dụng, và đó là tại sao chúng ta sử dụng Exception Handling.

Giả sử có 10 lệnh trong chương trình của bạn và xuất hiện một Exception tại lệnh 5, phần còn lại của code sẽ không được thực thi (từ lệnh 6 tới lệnh 10). Nếu chúng ta thực hiện Exception Handling, phần lệnh còn lại sẽ được thực thi. Đó là ý nghĩa của việc sử dụng Exception Handling trong Java.





II.Cấp bậc exception trong Java


Tất cả các lớp exception đều là lớp con của lớp java.lang.Exception . Lớp exception là lớp con của lớp Throwable. Một loại lớp exception khác là Error cũng là lớp con của lớp Throwable.
Erros không thường được đặt bẫy bởi các chương trình Java. Error thường được tạo ra để thể hiện lỗi trong môi trường runtime. Ví dụ: JVM hết bộ nhớ. Thông thường các chương trình không thể khôi phục từ các lỗi.
Lớp Exception có hai lớp con chính là : IOException RuntimeException.


III. Các phương thức và từ khóa của Exceptions

1.Các Phương thức:
STTPhương thức và Miêu tả
1public String getMessage()
Trả về một message cụ thể về exception đã xảy ra. Message này được khởi tạo bởi phương thức contructor của Throwable
2public Throwable getCause()
Trả về nguyên nhân xảy ra exception biểu diễn bởi đối tượng Throwable
3public String toString()
Trả về tên của lớp và kết hợp với kết quả từ phương thức getMessage()
4public void printStackTrace()
In ra kết quả của phương thức toString cùng với stack trace đến System.err
5public StackTraceElement [] getStackTrace()
Trả về một mảng chứa mỗi phần tử trên stack trace. Phần tử tại chỉ mục 0 biểu diễn phần trên cùng của Call Stack, và phần tử cuối cùng trong mảng biểu diễn phương thức tại dưới cùng của Call Stack
6public Throwable fillInStackTrace()
Fills the stack trace of this Throwable object with the current stack trace, adding to any previous information in the stack trace.

2. Các từ Khóa:
Có 5 từ khóa được sử dụng để Xử lý ngoại lệ trong Java:
- try

- catch

- finally

- throw

- throws


IV. Ưu, Nhược điểm


- Ưu điểm: Exception cung cấp các phương tiện để tách các lỗi xảy ra từ logic khỏi chương trình java. Trong java, việc phát hiện, báo cáo và xử lí lỗi thường làm cho mã lệnh khó hiểu.Exception cho phép bạn viết các luồng chính của mã lệnh của bạn để đối phó với những trường hợp đặc biệt ở những nơi khác nhau. Có khả năng chuyển lỗi lên call stack. Hệ thống sẽ tìm trong call stack phương thức chứa khối mã có thể xử lí ngoại lệ. Khối mã này được gọi là exceptionhandler. Phân nhóm và phân biệt các loại lỗi: Bởi vì tất cả các exception được ném vào chương trình là các đối tượng, nên việc nhóm hoặc phân loại các exception là kết quả tự nhiên của hệ thống phân cấp lớp. 

- Nhược điểm: Mỗi ngoại lệ khi sinh ra phải được xử lí, nếu không chương trình sẽ bị ngắt. Một số điểm cần chú ý RuntimeException và các lớp con của nó là một tập hợp con của UncheckesException Lớp Error và các lớp con của nó cũng không được kiểm tra tại thời điểm biên dịch nên cũng được coi là UncheckedException Giả sử Method1 gọi Method2 và Method2 là phương thức có khả năng ném ngoại lệ kiểu checked, lúc đó: hoặc Method2 phải nằm trong khối lệnh try...catch, hoặc phải khai báo Method1 có khả năng throws exception.


V. Ví dụ áp dụng

1.Bắt ngoại lệ thông qua try-catch:


AgeException.java
?
1
2
3
4
5
6
7
8
9
package org.o7planning.tutorial.exception.basic;
public class AgeException extends Exception {
  public AgeException(String message) {
      super(message);
  }
}
TooYoungException.java
?
1
2
3
4
5
6
7
8
9
package org.o7planning.tutorial.exception.basic;
public class TooYoungException extends AgeException {
 public TooYoungException(String message) {
     super(message);
 }
}
TooOldException.java
?
1
2
3
4
5
6
7
8
9
package org.o7planning.tutorial.exception.basic;
public class TooOldException extends AgeException {
 public TooOldException(String message) {
     super(message);
 }
}
Và class AgeUtils có method tĩnh dùng cho việc kiểm tra tuổi.
AgeUtils.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.o7planning.tutorial.exception.basic;
public class AgeUtils {
  // Method này làm nhiệm vụ kiểm tra tuổi.
  // Nếu tuổi nhỏ hơn 18 method sẽ ném ra ngoại lệ TooYoungException
  // Nếu tuổi lớn hơn 40 method sẽ ném ra ngoại lệ TooOldException
  public static void checkAge(int age) throws TooYoungException,
          TooOldException {
      if (age < 18) {
          // Nếu tuổi nhỏ hơn 18, ngoại lệ sẽ được ném ra
          // Method này kết thúc tại đây.
          throw new TooYoungException("Age " + age + " too young");
      } else if (age > 40) {
          // Nếu tuổi lớn hơn 40, ngoại lệ sẽ được ném ra.
          // Method này kết thúc tại đây.
          throw new TooOldException("Age " + age + " too old");
      }
      // Nếu tuổi nằm trong khoảng 18-40.
      // Đoạn code này sẽ được chạy.
      System.out.println("Age " + age + " OK!");
  }
}

2.Checked Exception và Unchecked Exception: 

AgeException là con của Exception, TooOldException TooYoungException là 2 class con trực tiếp của AgeException, nên chúng là các "Checked Exception" Trong method AgeUtils.checkAge(int) có ném ra ngoài các ngoại lệ này vì vậy trên khai báo của method bạn cần phải liệt kê chúng thông qua từ khóa "throws". Hoặc bạn có thể khai báo ném ra ở mức tổng quát hơn throws Exception. Tại các nơi sử dụng AgeUtils.checkAge(int) cũng phải có sử lý để bắt các ngoại lệ đó, hoặc tiếp tục ném ra vòng ngoài.


TryCatchDemo1.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package org.o7planning.tutorial.exception.basic;
public class TryCatchDemo1 {
  public static void main(String[] args) {
      // Bắt đầu tuyển dụng
      System.out.println("Start Recruiting ...");
      // Kiểm tra tuổi của bạn.
      System.out.println("Check your Age");
      int age = 50;
      try {
          AgeUtils.checkAge(age);
          System.out.println("You pass!");
      } catch (TooYoungException e) {
          // Làm gì đó tại đây ..
          System.out.println("You are too young, not pass!");
          System.out.println(e.getMessage());
      } catch (TooOldException e) {
          // Làm gì đó tại đây
          System.out.println("You are too old, not pass!");
          System.out.println(e.getMessage());
      }
  }
}
TryCatchDemo2.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.o7planning.tutorial.exception.basic;
public class TryCatchDemo2 {
  public static void main(String[] args) {
      // Bắt đầu tuyển dụng
      System.out.println("Start Recruiting ...");
      // Kiểm tra tuổi của bạn.
      System.out.println("Check your Age");
      int age = 15;
      try {
          // Chỗ này có thể bị ngoại lệ TooOldException,
          // hoặc TooYoungException
          AgeUtils.checkAge(age);
          System.out.println("You pass!");
      } catch (AgeException e) {
          // Nếu có ngoại lệ xẩy ra, kiểu AgeException
          // Khối catch này sẽ được chạy
          System.out.println("Your age invalid, you not pass");
          System.out.println(e.getMessage());
      }
  }
}
TryCatchDemo3.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package org.o7planning.tutorial.exception.basic;
public class TryCatchDemo3 {
  public static void main(String[] args) {
      // Bắt đầu tuyển dụng
      System.out.println("Start Recruiting ...");
      // Kiểm tra tuổi của bạn.
      System.out.println("Check your Age");
      int age = 15;
      try {
          // Chỗ này có thể bị ngoại lệ TooOldException,
          // hoặc TooYoungException
          AgeUtils.checkAge(age);
          System.out.println("You pass!");
      } catch (TooYoungException | TooOldException e) {
          // Gộp 2 ngoại lệ trong cùng một khối catch
          System.out.println("Your age invalid, you not pass");
          System.out.println(e.getMessage());
      }
  }
}

3.Khối try-catch-finally


TryCatchFinallyDemo.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package org.o7planning.tutorial.exception.basic;
public class TryCatchFinallyDemo {
   public static void main(String[] args) {
       String text = "001234A2";
       int value = toInteger(text);
       System.out.println("Value= " + value);
   }
   public static int toInteger(String text) {
       try {
           System.out.println("Begin parse text: " + text);
           // Tại đây có thể phát sinh ngoại lệ NumberFormatException
           int value = Integer.parseInt(text);
           return value;
       } catch (NumberFormatException e) {
           // Trong trường hợp 'text' không phải là số.
           // Khối catch này sẽ được thực thi.
           System.out.println("Number format exception " + e.getMessage());
           // NumberFormatException xẩy ra, trả về 0.
           return 0;
       } finally {
           System.out.println("End parse text: " + text);
       }
   }
}