Try catch Java là gì

Trong quá trình học tập, nghiên cứu hoặc trong một bài phỏng vấn về ngôn ngữ Java. Xử lý ngoại lệ là một vấn đề quan trọng giúp chúng ta có thể hoàn thiện, tối ưu một chương trình Java. Sau đây mình sẽ đề xuất 05 điều bạn cần biết về ngoại lệ và xử lý ngoại lệ trong Java.

1. Ngoại lệ trong Java là gì?

Một ngoại lệ [Exception] trong Java là một vấn đề phát sinh trong quá trình thực thi chương trình. Khi xảy ra ngoại lệ, luồng xử lý [flow] bị gián đoạn, chương trình/ứng dụng dừng bất thường. Nó là một đối tượng được ném ra tại Runtime.

Ngoại lệ trong Java có thể xảy ra vì nhiều lý do khác nhau:

  • Nhập dữ liệu không hợp lệ.
  • Không tìm thấy file cần mở.
  • Kết nối mạng bị ngắt trong quá trình thực hiện giao tác.
  • JVM hết bộ nhớ.
  • Truy cập vượt ngoài chỉ số của mảng, v…v…

Ngoại lệ xảy ra có thể do người dùng, lập trình viên hoặc số khác do tài nguyên bị lỗi. Java Exeption được triển khai bằng cách sử dụng các lớp như Throwable, Exception, RuntimeException và các từ khóa như throw, throws, try, catch và finally.

Dựa vào tính chất các vấn đề, người ta chia ngoại lệ thành ba loại:

  • Ngoại lệ được kiểm tra [Checked Exceptions].
  • Ngoại lệ không được kiểm tra [Unchecked Exceptions].
  • Lỗi [Error].

2. Sự khác nhau giữa "Checked Exceptions" và "Unchecked Exceptions" trong Java?

Checked Exceptions: Là một ngoại lệ được kiểm tra và thông báo bởi trình biên dịch tại thời điểm biên dịch, chúng cũng có thể được gọi là ngoại lệ thời gian biên dịch [Compile-time Exceptions]. Và lập trình viên không thể lường trước.

Ví dụ: Bạn muốn mở một file để đọc nhưng tệp được chỉ định lại không tồn tại. Thì FileNotFoundExeption sẻ xảy ra và trình biên dịch sẽ thông báo tới lập trình viên nhằm xử lý ngoại lệ đó.

Unchecked Exceptions: Là một ngoại lệ không được kiểm tra trong quá trình biên dịch. Chúng cũng được gọi là ngoại lệ thời gian chạy [Runtime Exceptions]. Là ngoại lệ có thể tránh được bởi lập trình viên. Unchecked Exceptions kế thừa từ Runtime Exception.

Ví dụ: ArithmaticException, ArrayIndexOutOfBoundsException, NullPointerException,…chúng được kiểm tra tại Runtime.

3. Sự khác nhau giữa hai từ khóa "throw" và "throws" trong Java?

Mặc dù trông giống nhau và đều được sử dụng trong xử lý ngoại lệ nhưng throw và throws khác nhau về cách thức sử dụng và nơi chúng được sử dụng trong code. 

Về throw, nó được sử dụng để ném ra một ngoại lệ cụ thể. Chúng ta có thể ném một trong hai ngoại lệ checked hoặc unchecked trong java bằng từ khóa này. Từ khóa throw chủ yếu được sử dụng để ném ngoại lệ do người dùng tự định nghĩa.

Ví dụ:

public class TestException { public static void main[String[] args] { ageValid[19]; System.out.println["------"]; ageValid[17]; } public static void ageValid[int age]{ 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!"]; } }

Checked Exception & Unchecked Exception:

  • AgeException là con của Exception, TooOldExceptionTooYoungException 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
  • 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.

"Checked exception" sẽ được "Java Compiler" kiểm tra.

Bạn có hai sự lựa chọn sử lý:

  1. Ném tiếp ra vòng ngoài
  2. Thực hiện việc bắt và sử lý ngoại lệ thông qua try-catch.

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. 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[]]; } } }

Ví dụ dưới đây, chúng ta sẽ gộp bắt các ngoại lệ thông qua ngoại lệ ở cấp cao hơn. Ở cấp cao hơn nó sẽ tóm được ngoại lệ đó và tất cả các ngoại lệ con.

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ể phát ra 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[]]; } } }

Bạn cũng có thể gộp xử lý các ngoại lệ khác nhau vào cùng một khối catch để sử lý nếu chúng có cách xử lý giống nhau trong logic chương trình của bạn.

package org.o7planning.tutorial.exception.basic; public class TryCatchDemo3 { public static void main[String[] args] { System.out.println["Start Recruiting ..."]; System.out.println["Check your Age"]; int age = 15; try { // Chỗ này có thể gây ra ngoại lệ TooOldException, // hoặc TooYoungException AgeUtils.checkAge[age]; System.out.println["You pass!"]; } catch [TooYoungException | TooOldException e] { // Bắt nhiều loại ngoại lệ trong 1 khối Catch. System.out.println["Your age invalid, you not pass"]; System.out.println[e.getMessage[]]; } } }

Trên kia chúng ta đã làm quen với việc bắt lỗi thông qua khối try-catch. Việc xử lý ngoại lệ đầy đủ là try-catch-finally.

try { // Làm gì đó tại đây. } catch [Exception1 e] { // Làm gì đó tại đây. } catch [Exception2 e] { // Làm gì đó tại đây. } finally { // Khối finally luôn luôn được thực thi. // Làm gì đó tại đây. }

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ể gây ra 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à một số. // Khối catch này sẽ được thực thi. System.out.println["Number format exception " + e.getMessage[]]; // Khi NumberFormatException xẩy ra, trả về 0. return 0; } finally { System.out.println["End parse text: " + text]; } } }

Đây là sơ luồng đi của chương trình. Khối finally luôn được thực thi.

Chúng ta cần một vài class tham gia vào ví dụ này:

  • Person: Mô phỏng một người tham gia tuyển dụng vào công ty với các thông tin
  • GenderException: Ngoại lệ giới tính.
  • ValidateException: Ngoại lệ đánh giá thí sinh.
  • ValidateUtils: Class có method tĩnh đánh giá thí sinh đủ tiêu chuẩn không.
    • Tiêu chuẩn là những người độ tuổi 18-40
    • Và là Nam.

package org.o7planning.tutorial.exception.wrap; public class Person { public static final String MALE = "male"; public static final String FEMALE = "female"; private String name; private String gender; private int age; public Person[String name, String gender, int age] { this.name = name; this.gender = gender; this.age = age; } public String getName[] { return name; } public void setName[String name] { this.name = name; } public String getGender[] { return gender; } public void setGender[String gender] { this.gender = gender; } public int getAge[] { return age; } public void setAge[int age] { this.age = age; } }

package org.o7planning.tutorial.exception.wrap; // Ngoại lệ Giới tính. public class GenderException extends Exception { public GenderException[String message] { super[message]; } }

Class ValidateException bao lấy một Exception khác.

package org.o7planning.tutorial.exception.wrap; public class ValidateException extends Exception { // Gói [wrap] Exception trong một Exception khác public ValidateException[Exception e] { super[e]; } }

package org.o7planning.tutorial.exception.wrap; import org.o7planning.tutorial.exception.basic.AgeUtils; public class ValidateUtils { // Phương thức kiểm tra 1 ứng viên. public static void checkPerson[Person person] throws ValidateException { try { // Kiểm tra tuổi. // Hợp lệ là trong khoảng 18-40 // Method này có thể ném ra TooOldException,TooYoungException. AgeUtils.checkAge[person.getAge[]]; } catch [Exception e] { // Nếu không hợp lệ // Gói ngoại lệ này bởi ValidateException, và ném ra [throw]. throw new ValidateException[e]; } // Nếu người này là Nữ, nghĩa là không hợp lệ. if [person.getGender[].equals[Person.FEMALE]] { GenderException e = new GenderException["Do not accept women"]; throw new ValidateException[e]; } } }

WrapperExceptionDemo.java

package org.o7planning.tutorial.exception.wrap; public class WrapperExceptionDemo { public static void main[String[] args] { // Một ứng viên. Person person = new Person["Marry", Person.FEMALE, 20]; try { // Ngoại lệ có thể xẩy ra tại đây. ValidateUtils.checkPerson[person]; } catch [ValidateException wrap] { // Lấy ra nguyên nhân thực sự. // Mà có thể là TooYoungException, TooOldException, GenderException. Exception cause = [Exception] wrap.getCause[]; if [cause != null] { System.out.println["Not pass, cause: " + cause.getMessage[]]; } else { System.out.println[wrap.getMessage[]]; } } } }

Class RuntimeException và các class con, cháu của nó đều là các "Unchecked exception". Nó không được bộ dịch java kiểm tra trong thời gian biên dịch. Trong một vài tình huống bạn có thể viết các exception của mình thừa kế từ nhánh này. Có một số ngoại lệ trong nhánh này sẵn có trong java mà bạn cần phải để mắt tới nó.

Dưới đây là một vài class thuộc nhánh RuntimeException [Tất nhiên không phải là tất cả].

Chúng ta thử một vài ví dụ xử lý các ngoại lệ kiểu này:

Đây là một trong các ngoại lệ thông dụng nhất, và hay gây ra lỗi cho chương trình. Ngoại lệ được ném ra khi bạn gọi phương thức hoặc truy cập vào các trường của một đối tượng chưa được khởi tạo [đối tượng null].

NullPointerExceptionDemo.java

package org.o7planning.tutorial.exception.runtime; public class NullPointerExceptionDemo { // Ví dụ đây là một method mà có thể trả về chuỗi null. public static String getString[] { if [1 == 2] { return "1==2 !!"; } return null; } public static void main[String[] args] { // Đây là một biến có tham chiếu khác null. String text1 = "Hello exception"; // Gọi phương thức để lấy ra độ dài chuỗi. int length = text1.length[]; System.out.println["Length text1 = " + length]; // Đây là một biến có tham chiếu null. String text2 = getString[]; // Gọi phương thức để lấy ra độ dài chuỗi. // NullPointerException sẽ xẩy ra tại đây. // Nó là ngoại lệ xuất hiện tại thời gian chạy [runtime]. // [Kiểu RuntimeException]. // Trình biên dịch [compiler] của Java không bắt buộc // bạn phải bắt [catch] nó tại thời điểm biên dịch [compile-time]. length = text2.length[]; // ==> exception! System.out.println["Finish!"]; } }

Length text1 = 15 Exception in thread "main" java.lang.NullPointerException at org.o7planning.tutorial.exception.runtime.NullPointerExceptionDemo.main[NullPointerExceptionDemo.java:51]

Trong thực tế giống việc xử lý các ngoại lệ khác, bạn có thể sử dụng try-catch để bắt ngoại lệ này mà xử lý. Tuy nhiên, đó là cách máy móc, thông thường chúng ta nên kiểm tra để đảm bảo rằng đối tượng là khác null trước khi sử dụng nó.

Bạn có thể sửa code trên giống dưới đây, để tránh NullPointerException:

// Phương thức getString[] trả về một giá trị null. // Đây là một đối tượng có tham chiếu null. String text2 = getString[]; // Kiểm tra để đảm bảo rằng text2 là khác null. // Thay vì sử dụng try-catch. if [text2 != null] { length = text2.length[]; }

Đây là ngoại lệ nó được ném ra khi bạn cố truy cập vào phần tử có chỉ số không hợp lệ trên mảng. Chẳng hạn mảng có 10 phần tử, mà bạn lại truy cập  vào phần tử có chỉ số 20.

ArrayIndexOfBoundsExceptionDemo.java

package org.o7planning.tutorial.exception.runtime; public class ArrayIndexOfBoundsExceptionDemo { public static void main[String[] args] { String[] strs = new String[] { "One", "Two", "Three" }; // Truy cập vào phần tử tại chỉ số 0. String str1 = strs[0]; System.out.println["String at 0 = " + str1]; // Truy cập vào phần tử tại chỉ số 5 // ArrayIndexOfBoundsException xẩy ra tại đây. String str2 = strs[5]; System.out.println["String at 5 = " + str2]; } }

Để tránh ArrayIndexOfBoundsException bạn nên kiểm tra mảng thay vì sử dụng try-catch.

if [strs.length > 5] { String str2 = strs[5]; System.out.println["String at 5 = " + str2]; } else { System.out.println["No elements with index 5"]; }

Video liên quan

Chủ Đề