1. Khối lệnh Try-Catch trong Java là gì?

Như ta đã biết khi thực hiện một đoạn code có thể có rất nhiều lỗi khác nhau có thể xảy ra mà ta không thể lường trước được. Lúc này khi xảy ra lỗi, ngoại lệ thì Java thông thường sẽ dừng thực thi chương trình và đưa ra một thông báo, hay nói cách khác là Java ném ra một exception – Ngoại lệ.

Lúc này quá trình xử lý ngoại lệ (exception) được gọi là bắt ngoại lệ hay catch exception . Nếu Runtime System không xử lý được ngoại lệ thì lúc này chương trình sẽ kết thúc. Và đoạn code bên trong khối lệnh try trong Java sẽ được sử dụng. Nó chứa một đoạn code thực thi mà trong quá trình ta thực thi nó có thể có ngoại lệ xảy ra. Sau khối lệnh try này ta phải khai báo khối lệnh là catch hoặc finally thậm chí là sử dụng cả 2 khối lệnh này. Những khối này sử dụng để xử lý nếu xảy ra Exception, nếu không thì nó bị bỏ qua. Khối catch phải được sử dụng ngay sau khối try . Ta có thể sử dụng nhiều khối catch với nhưng chỉ có một khối try duy nhất.

Ta có thể nhớ nôm na khối lệnh try-catch sử dụng để chứa một đoạn code để xử lý ngoại lệ sao cho chương trình thân thiện với người dùng hơn.

2. Cú pháp khối lệnh Try-Catch trong Java

Try block chứa tập hợp các câu lệnh có thể xảy ra ngoại lệ. Catch block là nơi ta xử lý các ngoại lệ, nó phải đi kèm với try block. Một try block có thể có một hoặc nhiều catch block.

Cú pháp :

try
{
     // Các câu lệnh có thể tạo ra exception
}
catch (exception(type) e(object))‏
{
     // Code xử lí exception 
}

Ta có thể bắt các Exception khác nhau trong các catch block khác nhau. Khi một Exception được tạo ra trong try block, đoạn code trong catch block tương ứng xử lý Exception đó sẽ được thực thi. Ví dụ: nếu một Exception số học xảy ra trong try block thì các câu lệnh được bao trong catch block dùng để xử lý Exception đó sẽ được thực thi.

Ngoài ra ta cũng có cú pháp của try finally trong Java

try {
  // code có thể ném ra ngoại lệ
} finally {
  // code trong khối này luôn được thực thi
}

Và cú pháp kết hợp của cả try catch finally trong Java

try {
  // code có thể ném ra ngoại lệ
} catch(Exception_class_Name_1 ex) {
  // code xử lý ngoại lệ 1
} catch(Exception_class_Name_2 ex) {
  // code xử lý ngoại lệ 2
} catch(Exception_class_Name_n ex) {
  // code xử lý ngoại lệ n
} finally {
  // code trong khối này luôn được thực thi
}

3. Ví dụ về try catch trong Java

Ta có một ví dụ đơn giản về việc sử dụng try catch để bắt lỗi và thực thi một số mã để xử lý nó:

public class Main {
  public static void main(String[] args) {
    try {
      int[] myNumbers = {1, 2, 3};
      System.out.println(myNumbers[10]);
    } catch (Exception e) {
      System.out.println("Đã xảy ra lỗi.");
    }
  }
}

Kết quả

Đã xảy ra lỗi.

Ở đây ta có câu lệnh in ra số 10. Như vậy đã xảy ra ngoại lệ ở đây vì không có số 10 trong chuỗi myNumbers . Nhưng vì ta đã cho nó vào trong khối lệnh try catch để bắt ngoại lệ này vì vậy mà ta đã in ra được dòng lệnh “Đã xảy ra lỗi” .

Một ví dụ khác về việc sử dụng finally thực thi try catch sau đó bất kể kết quả có như thế nào:

public class Main {
  public static void main(String[] args) {
    try {
      int[] myNumbers = {1, 2, 3};
      System.out.println(myNumbers[10]);
    } catch (Exception e) {
      System.out.println("Đã xảy ra lỗi.");
    } finally {
      System.out.println("Quá trình bắt ngoại lệ đã kết thúc.");
    }
  }
}

Kết quả

Đã xảy ra lỗi.
Quá trình bắt ngoại lệ đã kết thúc.

Hay một ví dụ với nhiều khối lệnh catch

class Main {
   public static void main(String args[]) {
      int num1, num2;
      try {
         /* Ta nghi ngờ rằng khối lệnh này sẽ throw ra
          * exception vì vậy ta sẽ xử lý nó bằng cách đặt các câu lệnh này
          * bên trong try block và xử lý exception trong catch block
          */
         num1 = 0;
         num2 = 62 / num1;
         System.out.println(num2);
         System.out.println("Kết thúc try block.");
      }
      catch (ArithmeticException e) { 
         /* Catch block này sẽ chỉ thực hiện nếu có ngoại lệ số học
          * xảy ra trong try block
          */
         System.out.println(" Lỗi: Số bị chia không thể là số 0");
      }
      catch (Exception e) {
         /* Đây là một exception chung, nó có thể xử lý
          * tất cả các exception.Catch block này sẽ thực thi nếu ngoại lệ không
          * được xử lý bởi catch block bên trên
          */
         System.out.println("Lỗi: một ngoại lệ đã xảy ra");
      }
      System.out.println("Ra khỏi try catch block.");
   }
}

Kết quả

 Lỗi: Số bị chia không thể là số 0
Ra khỏi try catch block.

Nếu một Exception xảy ra trong khối lệnh try thì chương trình sẽ thực thi các câu lệnh trong khối lệnh catch tương ứng. Một try block có thể có nhiều catch block được liên kết với nó, ta nên sắp xếp các catch block hợp lí sao cho catch block xử lý Exception chung ở cuối cùng.

Một Exception chung có thể xử lý tất cả các ngoại lệ nhưng bạn nên đặt ở cuối, nếu ta đặt nó ở trước tất cả các catch block khác thì nó sẽ hiển thị một thông báo chung cho tất cả trường hợp. Chắc chắn ta sẽ không muốn điều đó xảy ra.

4. Chú ý khi sử dụng try catch trong Java

Đầu tiên một try block có thể nhiều catch block. Nó là điều hoàn toàn bình thường và cơ bản nhất. Lúc mới bắt đầu tìm hiểu ta có thể thấy hơi rối nhưng rồi ta sẽ thấy được sự hữu ích của nó đấy.

Thứ hai một catch block xử lí Exception chung có thể xử lý tất cả các Exception, cho dù đó là ArrayIndexOutOfBoundException hay ArithaturesException hay NullPulumException hay bất kỳ loại Exception nào khác. Nếu ta đang thắc mắc tại sao chúng ta cần phải xử lí các Exception khác trong khi có thể code gọn hơn bằng cách catch Exception chung cho tất cả trường hợp. Thì ta phải nhớ rằng việc catch một Exception chung sẽ chỉ hiển thị cùng một thông báo cho tất cả các ngoại lệ, và người dùng hoặc có thể là chính ta sẽ không biết được Exception nào đang xảy ra. Đó là lý do nên đặt catch block xử lí Exception chung ở cuối.

Thức ba nếu không có Exception xảy ra trong try block thì catch block hoàn toàn bị bỏ qua.

Thứ tư các catch block tương ứng thực thi cho Exception cụ thể đó:

  • catch (ArithaturesException e) dùng để xử lí ngoại lệ ArithaturesException
  • catch (NullPulumException e) dùng để xử lí ngoại lệ NullPulumException

Ví dụ:

class Main{
   public static void main(String args[]){
     try{
         int a[]=new int[7];
         a[4]=30/0;
         System.out.println("Câu lệnh in đầu tiên trong try block");
     }
     catch(ArithmeticException e){
        System.out.println("Cảnh báo: ngoại lệ ArithmeticException");
     }
     catch(ArrayIndexOutOfBoundsException e){
        System.out.println("Cảnh báo: ngoại lệ ArrayIndexOutOfBoundsException");
     }
     catch(Exception e){
        System.out.println("Cảnh báo: ngoại lệ khác");
     }
   System.out.println("Ra khỏi try-catch block...");
  }
}

Kết quả

Cảnh báo: ngoại lệ ArithmeticException
Ra khỏi try-catch block...

Trong ví dụ trên có nhiều catch block và các catch block này thực hiện tuần tự khi có Exception xảy ra trong try block. Điều đó có nghĩa là nếu ta đặt catch block cuối cùng catch(Exception e) ở vị trí đầu tiên, ngay sau try block thì trong trường hợp có bất kỳ Exception nào. Khối này sẽ thực thi vì nó có thể xử lý tất cả các Exception. Catch block này nên được đặt ở cuối cùng để tránh những tình huống như vậy.