Code smell – Những lỗi thường gặp khi bắt đầu học lập trình(Set 1)

Vòng lặp

Vòng lặp là một một trong những cấu trúc lệnh của lập trình java mà chúng ta được tiếp xúc ngay từ đầu.

Để sử dụng vòng lặp thì rất đơn giản, thế nhưng các bạn có bao giờ hỏi mình sử dụng vòng lặp như thế là đúng hay chưa?

Các bạn xem ví dụ dưới đây

Vấn đề: Cho mảng số nguyên, in tất cả các phần tử của mảng ra console.

Bad code

public class Main {

    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,9};
        for(int i = 0; i < arr.length; i++)
            System.out.print(arr[i] + " ");
    }
}

Good code

public class Main {

    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,9};
        for (int value : arr) 
            System.out.print(value + " ");
    }
}

Các bạn thấy ở cách 1 và cách 2 đều làm cùng một nhiệm vụ đó là in tất cả các phần tử của mảng ra màn hình console.

Thế nhưng với cách 1 chúng ta sử dụng  for(int i = 0; i < arr.length; i++)  biến i được khởi tạo và tăng biến đếm mà không được sử dụng cho mục đích nào. 

Note: Trong trường hợp duyệt hoặc không quan tâm đến index của các phần tử trong mảng ta nên sử dụng cấu trúc for (int value : arr), còn nếu bạn cần sử dụng index của phần tử thì mới dùng cấu trúc trên nhé.

Rút trích dữ liệu

Cho một class Student

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@AllArgsConstructor
public class Student {
    private String name;
    private boolean isMale; // true - male or false female
    private int age;
    private int score;
    private List<String> course;

    public void print() {
        System.out.println(this.name + " - " + (isMale ? "Male" : "Female") + " - "+ this.age + " - " + this.score);
    }
}

Vấn đề: Lấy danh sách các sinh viên có điểm >=5 từ List<Student> 

Bad code

List<Student> result = new ArrayList<>();
for (int i = 0; i < result.size(); i++) {
    if (students.get(i).getScore() >= 5) {
        result.add(students.get(i));
    }
}

Good code

List<Student> result = students.stream().filter( s -> s.getScore() >= 5).collect(Collectors.toList());

Note:

Hồi sinh viên mình đã từng rất vất vả khi cần rút trích, xoá, tìm kiếm trong các collection. If else từa lưa còn sai lui sai tới vì logic quá phức tạp, code dài ngoằn. 

Thế nhưng mà một ngày nọ mình đã biết đến stream api và cách sử dụng của nó. 

Thao tác với các collection giờ đây thật dễ dàng, chúng ra có thể trích xuất, delete, kiếm tra các tính chất của dữ liệu, Group by,… với stream api.

Câu điều kiện

Câu điều kiện cũng là một trong những cấu trúc lệnh chúng ta sử dụng hằng ngày để code, thế nhưng có vài tình huống chúng ta không để ý thì câu điều kiện trở thành một đoạn tấu hài đấy. Xem đây

Vấn đề: Mình cần viết hàm kiểm tra sinh viên có đậu hay rớt bằng cách nếu score >= 5 thì đậu ngược lại thì rớt.

Bad code

public static boolean isPass(int score) {
        if (score >= 5)
            return true;
        else
            return false;
}

Good code

public static boolean isPass(int score) {
        return score >=5;
}

Note: Đừng có if else gì hết =) kết quả của điều kiện là thứ chúng ta cần.

Vấn đề: Trả về true nếu học sinh là nam và có điểm >= 5

Bad code

 public static boolean isMaleAndPass(Student student) {
        if (student.isMale()) {
            if (student.getScore() >= 5)
                return true;
        }
        return false;
}

Good code

public static boolean isMaleAndPass(Student student) {
        return student.isMale() && student.getScore() >= 5;
}

Note: Đôi lúc chúng ta cần hoà quyện vào nhau

Vấn đề: If else dài ngoằn

Bad code

if () ...
else if...
else if ...
else

Good code

switch () {
    case 1: 
    case 2:
    case n:
    default:
}

Note: If else nhiều quá thì nên dùng switch – case nhé.

So sánh

public enum Level {
    LOW,
    MEDIUM,
    HIGH
}

public class Staff {
    private Level level;
    private String name;
}

Vấn đề: Mình có class Level Staff như trên, bây giờ mình muốn so sánh Level của Staff.

Bad code

public class Main {
    public static void main(String[] args) {
        Staff staff = new Staff(null, "A");
        System.out.println(staff.getLevel().equals(Level.HIGH));
    }
}

Ở trên mình new Staff với level bằng null, khi sử dụng equals nó sẽ báo NullPointerException.

Các bạn nên viết ngược lại như sau, lưu ý này chỉ áp dụng cho java. Ngôn ngữ khác mình hông chắc =). 

Good code

System.out.println(Level.HIGH.equals(staff.getLevel()));

Exception 

Khi catch nhiều exception cùng lúc bạn nên để exception theo mức độ detail

Staff staff = null;
try {
    System.out.println(staff.getLevel());
}
catch (Exception e) {
    System.out.println();
}
catch (NullPointerException e) {
    e.printStackTrace();
}

Note: Như code ở trên bạn sẽ không bao giờ bắt được NullPointerException, vì catch sẽ chạy từ trên xuống dưới, nếu một catch nào bắt exception thì các catch ở phía sau sẽ dừng. 

Ở trên Exception là lớp cha của NullPointerException nên nó sẽ bắt trước và chúng ta sẽ không bao giờ có được kết quả mong muốn. Tuy nhiên hiện nay nhiều IDE hỗ trợ cho mình chuyện này, nó sẽ báo lỗi nếu chúng ta đặt catch một exception lớp cha trước lớp con.

Vấn đề: Bỏ qua exception

try {
    // do something
}
 catch (NumberFormatException e) {
    // skip
}

Note: Đừng bao giờ bỏ qua một exception nào hết nhé. Ít nhất bạn cũng phải printStackTrace() để sau này lỗi còn biết đường sai chỗ nào, chứ bỏ qua là sau này không biết tìm chỗ nào luôn đó =).

0 0 votes
Article Rating
Subscribe
Notify of
guest
2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
2
0
Would love your thoughts, please comment.x
()
x