Các lỗi thường gặp với newbie java

Bài viết gốc: https://codelearn.io/sharing/5-loi-oai-oam-ha-guc-newbie-khi-lap-trinh-java

Không khai báo biến và Không khởi tạo biến

“Error: cannot find symbol – Không khai báo biến”

Error: variable a might not have been initialized” – Không khởi tạo biến

Chắc chắn đây là 2 lỗi mà bất kì một lập trình viên Java nào cũng từng gặp phải. Nhiều khi bạn viết xong một đoạn code và chạy thử nhưng khi chạy thì “đỏ lòm” sau một hồi loay hoay thì bạn chợt nhận ra rằng mình chưa khai báo biến nào đó mà đã sử dụng nó rồi. Hoặc đôi khi bạn đã khai báo biến sau đó chạy chương trình thì lại nhận được thông báo lỗi. Loay hoay một hồi, google các kiểu bạn chợt nhận ra chẳng qua mình đã khai báo một biến nào đó nhưng không gán cho nó một giá trị cụ thể… 2 lỗi căn bản này rất dễ gặp ngay cả với những người lập trình thường xuyên. Về cơ bản thì đây là lỗi hoàn toàn đến từ lập trình viên, chỉ cần bạn chú ý sẽ không mắc phải nữa.

=> Một mẹo đơn giản là mỗi khi cần sử dụng các biến bạn nên khai báo “hàng loạt” các biến cần sử dụng, khi khai báo hãy khởi tạo ngay một giá trị cho nó. Chẳng hạn:

int a = 0, b = 0;
String s = "", m = "";

Lỗi “missing return statement” hoặc “error: incompatible types:…”
Lỗi này thường hay gặp phải với những người trót lười biếng khi thường viết code thẳng trong main, vừa nhanh vừa tiện đỡ phải gọi hàm rồi viết hàm lằng nhằng. Mà bạn biết đó, trong main thì đâu cần trả về gì, chỉ cần khai báo rồi dùng luôn. Cho đến khi tách hàm, bạn thường quen chỉ viết các câu lệnh mà quên mất mình phải return hay return sai kiểu mà lẽ ra bạn cần phải trả về.

=> Lỗi này có thể xử lý êm đẹp khi chúng ta có thói quen tách hàm khi code. Và thay vì code từng hàm một sau khi khai báo, ta nên tạo hàng loạt những hàm mình cần code và return về một giá trị mặc định nào đó trước khi bắt đầu viết phần thân cho mỗi hàm. Bạn có thể comment để nhìn code dễ và rõ ràng hơn

Ví dụ:

// Create new number from two integer
private static int createNumber(int x, int y) {
    return 0;
}

// Return a String by append a double
private static String getString(String n, double m) {
    return "";
}

// Create new array by given String
private static int[] createArray(String s) {
    return null;
} 

Lỗi số-chữ, chữ-chữ

Đúng vậy đó, một lỗi mà nhiều khi khiến chúng ta điên đầu chẳng phải chỉ với Java. Mặc dù hiện tại lỗi này ít khi xảy ra nhưng một số trường hợp nếu không để ý bạn có thể sẽ gặp lỗi mà không biết mình sai ở đâu.

Chẳng hạn khi bạn đặt một biến với tên là I hay O và một lát sau chạy code thì bạn nhân được những thông báo lỗi. Rất có thể bạn nhầm “Chữ O” và “Số 0”, Hay “Chữ lờ viết thường” và “Chữ i ngắn viết hoa”.  Bởi vậy khi đặt tên biến nên hạn chế đặt tên biến có chứa “l”, “I”, “0”, “O”, “vv”, “w” nếu chúng không tạo nên các từ có nghĩa. Tôi từng có một anh bạn gặp lỗi này và mất tới 30 phút mới tìm ra được lỗi sai ở đâu. Thực ra không có anh bạn nào cả, đúng, là tôi đó.

In tất cả với câu lệnh kì diệu System.out.println(…);

Mới học Java, ai cũng được dạy dữ liệu sẽ được in ra với câu lệnh huyền thoại System.out.println(...);. Càng ngày các loại dữ liệu mà ta học càng trở nên phức tạp, rồi một ngày nào đó, bạn khai báo 1 mảng rồi gán các giá trị cho mảng đó. Sau đó, bạn hồn nhiên in mảng ra và kết quả nhận được là một thứ kì lạ nào đó ví dụ:

public static void main(String agrs[]) {
        int [] arr= {1, 2, 3, 4, 5};
        System.out.println(arr);
}
// Đầu ra của chương trình: [I@4f023edb

Điều này rốt cục là sao? Java hay lỗi vậy? 

Thực tế không có lỗi nào ở đây cả. Là do bạn làm chưa đúng thôi! Bạn nên nhớ rằng System.out.println(...);  sẽ in ra một String, và với mọi tham số đầu và sẽ đều được convert sang kiểu String. Với những biến nguyên thủy mà ta thường in trực tiếp, việc convert sang String được thực hiện ngầm và giá trị (về mặt hiển thị) của chúng được giữ nguyên. Với một biến kiểu object, chẳng hạn array thì chúng sẽ được convert ngầm bằng phương thức toString() của lớp object. Phương thức đó như sau:

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

Bạn không cần hiểu hết đoạn code này làm gì đâu, nhưng chính nó là nguyên nhân tạo ra output [I@4f023edb của ví dụ bên trên, nếu để ý kĩ 4f023edb là một biểu diễn của một số hệ thập lục phân, bạn convert lại về hệ thập phân, biết đâu lại tìm ra được điều gì. 

Vậy in như thế nào?

Tin vui cho bạn là bạn cũng chỉ cần viết 1 câu lệnh ngắn như bên dưới để in cả một mảng.

System.out.println(Arrays.toString(arr));

Nó ngắn như vậy nhưng thực ra phương thức toString(); của lớp Arrays rất khác. Mà thôi đừng bận tâm, biết cách dùng để không gặp lỗi tương tự thôi đã là tốt rồi. 

Lỗi nuốt lệnh hay trôi lệnh khi nhập dữ liệu

Đây là một lỗi kinh điển mà lập trình viên gặp phải cực kì nhiều khi nhập liên tục các kiểu dữ liệu khác nhau

Đây là phương thức main của chương trình nhập và xuất thông tin của sinh viên:

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // Nhập
        System.out.println("Enter name: ");
        String name = sc.nextLine();
        System.out.println("Enter age: ");
        int age = sc.nextInt();
        System.out.println("Enter grade: ");
        String grade = sc.nextLine();
        System.out.println("Enter Address: ");
        String address = sc.nextLine();
        // Xuất
        System.out.println("Information:");
        System.out.println("Name is: " + name);
        System.out.println("Age is: " + age);
        System.out.println("Grade is: " + grade);
        System.out.println("Address is: " + address);
}

Kết quả sau khi chạy chương trình là đây:

Có thể thấy khi chạy chương trình, lệnh String grade = sc.nextLine(); đã không được thực thi. Tại sao điều này lại xảy ra? Java lỗi ư? Hay mình code sai? Một loạt câu hỏi sẽ được đưa ra và chắc chắn bạn sẽ không có câu trả lời và nếu không biết cách tìm kiếm lỗi cũng như xung quanh bạn không có ai có câu trả lời thì việc giải quyết vấn đề này sẽ không hề có phương hướng hoặc nếu giải quyết được thì đó là do “may mắn”. Ở một lần khác bị lỗi tương tự bạn sẽ lại mò mẫm để tìm cách fix.

Vậy lỗi ở đâu ra?

Bản chất vấn đề ở đây chính là việc khi bạn nhập dữ liệu thì phải dùng phím Enter. Bạn nhớ chứ khi bạn dùng lệnh in ra màn hình mà muốn ngắt dòng thì có thể dùng  ‘\n’ ở vị trí mà bạn muốn ngắt dòng. Khi bạn nhấn phím Enter thì chính xác bạn vừa nhập ‘\n’ đó. Bởi vậy khi chạy xong lệnh int age = sc.nextInt(); thì ‘\n’ đã được lưu trong bộ đệm. Khi bạn thực hiện lệnh String grade = sc.nextLine(); tiếp theo thì nó sẽ ngay lập tức nhận ‘\n’ là kết quả. Bởi lẽ sc.nextLine() cho phép ta nhập 1 String và ‘\n’ trong trường hợp này được xem là “\n”. Thực tế lệnh không bị nuốt, Java không lỗi và ta còn làm được một công đôi việc. Tuy nhiên một công đôi việc trong trường hợp này khiến ta đau đầu hơn. Đúng là cái gì tốt quá cũng chưa chắc đã tốt thật.

Vậy “lỗi” này fix ra sao?

Có 2 cách đơn giản để bạn có thể lựa chọn giải quyết vấn đề này:

Cách 1: Ép kiểu

Chẳng phải nếu bạn cứ nhập String liên tục thì sẽ không có gì thừa ra gây lỗi đúng không? Vậy để nhập các biến có kiểu dữ liệu khác nhau bạn có thể sử dụng cách nhập toàn bộ bằng sc.nextLine() và thực hiện ép kiểu. Có 2 phương thức tôi thường sử dụng trong bài toán cụ thể mà tôi vừa đưa ra:

int age = Integer.valueOf(sc.nextLine()); 
//or
int age = Integer.parseInt(sc.nextLine());

Cách 2: Loại bỏ phần thừa

Sử dụng thêm một lệnh sc.nextLine(); ngay sau int age = sc.nextInt(); mục đích của việc gọi lại lệnh này là để không còn ký tự enter nào thừa nữa. Nếu muốn tìm hiểu sâu bạn cứ ấn phím Ctrl và ấn vào nextLine để xem thực chất nó hoạt động như thế nào. Nếu không thì chỉ cần biết cách sửa là đã thành công rồi.

Tôi hay dùng cách 1 hơn, đơn giản nhìn nó “ngầu hơn” một chút.

Lỗi ẩu, vội vàng

Đúng vậy, lỗi nào cũng có thể fix và ai cũng có thể gặp những lỗi rât cơ bản. Tester thường có câu: “Khi bạn không thấy lỗi không có nghĩa là chương trình không có lỗi”. Chỉ khi bạn code một cách cẩn thận thì lỗi mới trở nên ít đi và chương trình mới chạy “êm” được. Tác phong nhanh nhẹn là tốt nhưng không phải cứ code nhanh là tốt và hiệu quả. Nhanh phải đi kèm với đúng và đủ mới tạo ra được thành quả. 

Bài viết không thể đề cập đến tất cả những lỗi thường gặp, tuy nhiên đây là những lỗi thường hay mắc phải nhất đối với những người mới học lập trình, đặc biệt là Java. Có thể chúng không phải thực sự là lỗi nhưng về mặt bản chất thì không đúng chính là sai, mà đã sai thì chắc chắn có lỗi… Cứ code và fix bug thôi. Hẹn gặp các bạn trong phần tiếp theo.

Bài viết gốc: https://codelearn.io/sharing/5-loi-oai-oam-ha-guc-newbie-khi-lap-trinh-java

Leave a Reply

Your email address will not be published. Required fields are marked *