Cách bắt lỗi khi nhập vào ngày không hợp lệ năm 2024

Lỗi là những lỗi phát sinh trong quá trình biên dịch hoặc trong quá trình thực thi chương trình. Lỗi có thể đến từ nhiều phía: do dữ liệu người dùng nhập vào ko đúng định dạng, do lập trình viên ko soát hết các trường hợp ko như ý muốn, hay các lỗi bất thường.

Chúng ta hay gọi chung là “lỗi”, chứ lỗi được phân chia làm 3 loại:

  1. Lỗi cấu hình hệ thống: cái này do bạn cài đặt JDK hay Eclipse có vấn đề như ko đúng nền tảng, thiếu file, thiếu thư viện, …
  2. Lỗi biên dịch: lỗi này chủ yếu là do sai cú pháp, hoặc phạm vi truy cập thuộc tính, phương thức sai. Những lỗi dạng này được kiểm soát trong quá trình biên dịch, và thường các trình biên tập code hỗ trợ thông báo ngay khi soạn thảo.
  3. Lỗi thực thi: lỗi thực thi thì được chia làm 3 loại:
  4. Lỗi bất thường (Error): do chương trình quá lạm dụng vào tài nguyên của máy tính mà máy tính ko thể đáp ứng đủ, ví dụ như:
    • Lỗi tràn ngăn xếp (StackOverflowError): do thực thi quá trình phép toán dẫn đến tràn vùng nhớ Stack. Các bài toán dùng thuật đệ quy hay bị lỗi này.
    • Lỗi tràn bộ nhớ (OutOfMemory): RAM ko đủ, chủ yếu là do số lượng đối tượng cần lưu trữ quá nhiều.
    • Lỗi liên kết thư viện ko đúng (LinkageError): do đường dẫn tới thư viện bên ngoài ko đúng.
  5. Ngoại lệ (Exception): là những lỗi do lập trình viên lý tưởng hoá điều kiện bài toán mà ko lường trước những trường hợp ngoại lệ.
    • NullPointerException: lỗi này rất dễ mắc phải, do người lập trình quên ko khởi tạo giá trị, hoặc cố làm việc trên một đối tượng rỗng.
    • NumberFormatException: lỗi khi cố gắng chuyển đổi chuỗi sang định dạng số, mà chuỗi đó chứa ký tự ko phải là số.
    • ArithmeticException: lỗi này xảy ra khi thực hiện phép toán số học vô nghĩa, ví dụ chia cho 0, căn số âm, …
    • IndexOutOfBoundException, Array IndexOutOfBoundException: lỗi xảy ra khi cố gắng truy cập vào phần tử mà chỉ số của phần tử vượt quá giới hạn của mảng. Ví dụ mảng chỉ có 3 phần tử mà bạn cố gắng lấy phần tử thứ 4.
    • FileNotFoundException: file ko tồn tại.
    • IOException: lỗi trong quá trình đọc ghi file.
  6. Lỗi thuật toán: lỗi này chỉ do thuật toán bạn sai nên kết quả đầu ra bị sai, chứ ko làm chết chương trình.

Cách xử lý các ngoại lệ :

Nếu có thể dự đoán được các trường hợp lỗi có thể xảy ra thì cố gắng sử dụng if…else để xử lý các trường hợp. Còn không thì hẵng dùng try…catch để bắt lỗi và xử lý lỗi.

try…catch và xử lý lỗi luôn tại catch :

String chuoiA = "24"; String chuoiB = "12"; try { int a = Integer.parseInt(chuoiA); int b = Integer.parseInt(chuoiB); double thuong = (double) a / b; System.out.println("Thương a/b = " + thuong); } catch (NumberFormatException e) { System.out.println("Lỗi chuyển đổi định dạng số."); } catch (ArithmeticException e2) { System.out.println("Lỗi chia cho 0."); }

Cùng một khối try nhưng có thể có nhiều khối catch cũng được.

Chương trình sẽ thực hiện khối lệnh trong try. Nếu gặp lỗi, chương trình sẽ lập tức nhảy sang khối catch, tuỳ vào việc bạn bắt lỗi nào thì khối lệnh trong catch tương ứng sẽ được thực thi. Sau khi hết khối catch thì chương trình sẽ chạy tiếp code ở bên dưới bên ngoài vòng try…catch. Nếu ko gặp lỗi, chương trình sẽ chạy hết try mà ko vào catch.

Bên cạnh lệnh try…catch còn có lệnh try…catch…finally. Khi gặp lỗi ở dòng nào đó trong try, chương trình ngay lập tức nhảy vào catch, nên những lệnh ở bên dưới lệnh mà bị lỗi đó sẽ ko được thực thi. Trong trường hợp dù lỗi hay ko có lỗi, bạn vẫn muốn thực hiện gì đó, ví dụ trong đọc ghi file cần phải có đóng luồng đọc ghi, bất kể có lỗi hay ko, thì khối finally sẽ giúp bạn thực hiện điều đó.

throw và throws :

Trong trường hợp bạn ko muốn xử lý lỗi ngay trong catch, mà muốn gửi lỗi đó cho một đối tượng khác xử lý, thì bạn chỉ cần quăng lỗi ra bằng throw hoặc throws. Throw được sử dụng ngay trong thân phương thức, còn throws thì khai báo trên đầu của phương thức.

try { int a = Integer.parseInt(chuoiA); } catch(NumberFormatException e) { throw e; }

public int chuyenDoiChuoiA() throws NumberFormatException { int a = Integer.parseInt(chuoiA); return a; }

Nếu bạn dùng throw thì bắt buộc phương thức chứa nó phải khai báo throws (Eclipse sẽ tự gợi ý cho bạn làm điều này). Đồng thời bạn phải viết try…catch tại nơi gọi phương thức đó.

Đọc, ghi trong Java :

Đọc từ bàn phím:

Scanner sc = new Scanner(System.in); System.out.println("Nhập họ tên:"); String name = sc.nextLine(); // xử lý xong xuôi, nhớ đóng luồng đọc sc.close();

Trên đây là ví dụ đơn giản cách đọc chuỗi kí tự từ bàn phím. Việc cần làm là khởi tạo đối tượng Scanner với luồng đầu vào là bàn phím “System.in”. Phương thức nextLine() để đọc một chuỗi các kí tự, hay

try { int a = Integer.parseInt(chuoiA); } catch(NumberFormatException e) { throw e; }

0 để đọc số nguyên, ngoài ra còn có các phương thức khác như nextBoolean(), nextDouble(), …. tương ứng với kiểu dữ liệu mà bạn cần đọc.

Khi bạn đọc số rồi sau đó đọc chuỗi, bạn sẽ gặp tình trạng ko đọc được chuỗi. Nguyên nhân là do dữ liệu nhập từ bàn phím ko phải bắt đầu đọc từ lúc phương thức ấy chạy, mà nó tạm thời lưu trong bộ nhớ đệm. Khi bạn nhập số rồi nhấn enter, phương thức nextInt() chỉ đọc các chữ số mà bỏ lại dấu xuống dòng (enter) trong bộ nhớ đệm. Phương thức nextLine() thì lấy trong bộ đệm một chuỗi cho đến khi kết thúc bởi dấu xuống dòng. Mà lúc này, nó gặp ngay dấu xuống dòng đầu tiên trong bộ nhớ đệm, nên trả về luôn một chuỗi rỗng. Có 2 cách để chữa: một là chèn thêm lệnh nextLine() ngay sau khi đọc số để nó thải bớt dấu xuống dòng ra khỏi bộ nhớ đệm, hai là ko dùng nextInt() nữa mà thay bằng nextLine() đồng thời chuyển đổi chuỗi đọc được sang dạng số luôn bằng phương thức Integer.parseInt(). Cách 2 này nên dùng vì ta có thể áp dụng để chuyển đổi các kiểu dữ liệu khác nhau. À tất nhiên, muốn parse thành công phải đặt lệnh trong khối try…catch, phòng trường hợp chuỗi nhập vào có chứa cả kí tự ko phải số.

try { System.out.println("Nhập tuổi:"); int age = Integer.parseInt(sc.nextLine()); System.out.println("Nhập địa chỉ:"); String address = sc.nextLine(); System.out.println(age + "_" + address); } catch (NumberFormatException e) { System.err.println("Không thể chuyển đổi chuỗi sang số."); } sc.close();

Đọc file:

public String readFile (String path) { String data = ""; try {

// bước 1: tạo đối tượng File để trỏ vào file cần đọc
File file = new File(path);
// bước 2: kiểm tra xem file đó có tồn tại ko
// nếu ko thì thoát luôn
if(!file.exists()) {
  System.err.println("File này không tồn tại.");
  return data;
}
// bước 3: tạo đối tượng FileInputStream để mở luồng đọc file
FileInputStream in = new FileInputStream(file);
// bước 4: đọc file
// 4.1: đọc theo từng mảng byte một, kích thước 1024 byte
byte[] buffer = new byte[1024];
int length = in.read(buffer);
while (length > 0) {
  // 4.2: chừng nào mảng byte còn chứa dữ liệu, chuyển hoá
  // mảng byte thành chuỗi String rồi cộng dồn vào biến chứa
  data += new String(buffer, 0, length);
  length = in.read(buffer);
}
// bước 5: đóng luồng đọc file
in.close();
} catch (IOException e) {
e.printStackTrace();
} // trả kết quả đọc được cho phương thức return data; }

Ghi file:

public void writeFile (String path, String data, boolean isAppend) { try {

// bước 1: tạo đối tượng File để trỏ vào file cần ghi
File file = new File(path);
// bước 2: kiểm tra xem file đó có tồn tại ko
// nếu ko thì tạo mới file
if(!file.exists()) {
  // 2.1: tạo mới các thư mục con nếu chúng chưa tồn tại
  file.getParentFile().mkdirs();
  // 2.2: tạo mới file
  file.createNewFile();
}
// bước 3: tạo đối tượng FileOutputStream để mở luồng ghi file
// isAppend bằng true là ghi tiếp vào cuối,
// false là xoá đi viết lại (ghi đè)
FileOutputStream out = new FileOutputStream(file, isAppend);
// bước 4: ghi file
// 4.1: chuyển toàn bộ dữ liệu từ String sang mảng byte
byte[] buffer = data.getBytes();
// 4.2: ghi mảng byte đó vào file
out.write(buffer);
// bước 5: đóng luồng ghi file
out.close();
} catch (IOException e) {
e.printStackTrace();
} }

Đọc, ghi object:

Đọc, ghi object có lợi thế là dữ liệu được ra, vào dưới dạng object, điều này vừa giúp chúng ta bỏ qua quy cách trình bày dữ liệu, vừa dễ dàng thể hiện nhiều thuộc tính.