JavaRush /Blog Java /Random-VI /10 sai lầm thường gặp của các nhà phát triển Java
theGrass
Mức độ
Саратов

10 sai lầm thường gặp của các nhà phát triển Java

Xuất bản trong nhóm
10 lỗi các lập trình viên Java thường mắc phải - 1
Danh sách này bao gồm 10 lỗi mà các nhà phát triển Java thường mắc phải.
  1. Chuyển đổi một mảng thành ArrayList .

    Để chuyển đổi một mảng thành ArrayList , các nhà phát triển thường sử dụng phương pháp này:

    List<String> list = Arrays.asList(arr);

    Arrays.asList()sẽ trả về một đối tượng lớp ArrayListlà một lớp tĩnh riêng tư bên trong (private static class)của lớp Arraysvà đây không phải là một lớp. java.util.ArrayList.Lớp này java.util.Arrays.ArrayListchứa các phương thức set(), get(), contains(), nhưng không chứa bất kỳ phương thức nào để thêm phần tử, kích thước của nó là cố định . Để tạo một cái thực sự java.util.ArrayList, hãy làm điều này:

    ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

    Một hàm tạo của lớp java.util.ArrayListcó thể lấy làm tham số cho tất cả các đối tượng thực hiện một giao diện Collection, việc triển khai giao diện này được lớp kế thừajava.util.Arrays.ArrayList

    (lớp tĩnh riêng ArrayList<E> mở rộng Tóm tắt<E> triển khai RandomAccess, java.io.Serializable).

  2. Kiểm tra một mảng cho một giá trị cụ thể.

    Các nhà phát triển thường làm điều này:

    Set<String> set = new HashSet<String>(Arrays.asList(arr));
    return set.contains(targetValue);

    Mã này hoạt động nhưng không cần phải chuyển đổi nó Listthành Set. Việc chuyển đổi sang Setsẽ mất thêm thời gian. Trên thực tế, mọi thứ đều đơn giản:

    Arrays.asList(arr).contains(targetValue);

    hoặc

    for(String s: arr){
    	if(s.equals(targetValue))
    		return true;
    }
    return false;

    Phương pháp đầu tiên ngắn hơn nhiều.

  3. Loại bỏ một phần tử khỏi Listvòng lặp

    Hãy xem xét đoạn mã sau để loại bỏ các phần tử trong một vòng lặp:

    ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
    for (int i = 0; i < list.size(); i++) {
    	list.remove(i);
    }
    System.out.println(list);

    Phần kết luận:

    [b, d]

    Điều này hóa ra là một sai lầm nghiêm trọng. Khi một phần tử bị loại bỏ, kích thước Listsẽ giảm và chỉ số phần tử thay đổi.

    Vì vậy, hãy tránh phương pháp này nếu bạn muốn xóa nhiều phần tử trong một vòng lặp bằng chỉ mục.

    Bạn có thể biết rằng sử dụng vòng lặp là giải pháp chính xác để loại bỏ các phần tử trong vòng lặp và bạn biết rằng vòng lặp kiểu for-eachhoạt động giống như một vòng lặp, nhưng thực tế không phải vậy.

    Hãy xem xét đoạn mã sau:

    ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
    
    for (String s : list) {
    	if (s.equals("a"))
    		list.remove(s);
    }

    Chúng tôi sẽ nhận được ConcurrentModificationException .

    Điều đúng đắn cần làm là:

    ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
    Iterator<String> iter = list.iterator();
    while (iter.hasNext()) {
    	String s = iter.next();
    
    	if (s.equals("a")) {
    		iter.remove();
    	}
    }

    Phương thức này next()phải được gọi trước remove().

    Trong kiểu vòng lặp for-each, trình biên dịch sẽ gọi phương thức này remove()và chỉ sau đó next()nó mới gây ra lỗi ConcurrentModificationException. Bạn có thể nhìn vào mã ArrayList.iterator().

  4. Hashtablechống lại HashMap.

    Do cách triển khai tương ứng nên Hashtable là tên của cấu trúc dữ liệu.

    Nhưng trong Java tên của cấu trúc dữ liệu là HashMap. Một trong những điểm khác biệt chính giữa Hashtableand HashMaplà nó được Hashtableđồng bộ hóa nên không nên sử dụng Hashtableở đâu HashMap.

    HashMap so với Bản đồ cây so với Bảng băm so với LinkedHashMap .

    10 câu hỏi cơ bản về giao diện Map

  5. Sử dụng bộ sưu tập không hạn chế nội dung

    В Java часто путают коллекции без ограничений по содержимому, и коллекции с маской по типу содержимого. К примеру, для множеств - Set это коллекция без ограничений по содержимому, а Set<?> — коллекция у которой все-таки есть ограничения, но эти ограничения ничего на самом деле не ограничивают. Рассмотрим следующий code, где List без ограничений используется в качестве параметра метода:

    public static void add(List list, Object o){
    	list.add(o);
    }
    public static void main(String[] args){
    	List<String> list = new ArrayList<String>();
    	add(list, 10);
    	String s = list.get(0);
    }

    Данный code выбросит исключение:

    Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    	at …

    Использование коллекций без ограничений по содержимому очень опасно, потому что вы не можете быть уверенными в том что там лежит внутри. А для того чтобы понять всю глубину разницы между Set, Set<?> и Set<Object> — почитайте вот эту и эту ссылки.

  6. Уровень доступа

    Очень часто для полей класса разработчики используют модификатор доступа public. Так проще получить meaning поля напрямую. Правильнее использовать How можно более ограниченный доступ к членам класса.

    public, default, protected, and private.

  7. ArrayList против LinkedList

    Когда разработчики не знают чем отличается ArrayList от LinkedList, они используют первый в силу его большей известности. Однако, есть огромная разница в производительности между ними. На самом деле, выбор между ними должен быть продиктован их внутренними особенностями — ArrayList позволяет быстро производить доступ к произвольному элементу массива, а LinkedList — быстро добавлять/удалять элементы в массиве. Почитайте статью по ссылке ArrayList vs. LinkedList чтобы понять причины их разной производительности.

  8. Mutable (Изменяемый) против Immutable (Неизменяемый)

    Неизменяемый an object имеет много преимуществ: простота, безопасность и т.д. Но он требует отдельного an object для каждого нового значения, и за слишком большое количество an objectов придется заплатить понижением производительности. Должен быть баланс при выборе между изменяемым и неизменяемым обьектом.

    В основном чтобы избежать подготовки промежуточных an objectов используется изменяемый an object. Один из классических примеров это конкатенация большого количества строк. Если вы используете неизменяемый an object типа String, то вы создаете много an objectов, которые сразу попадут в сборщик мусора. Это тратит время и энергию процессора, поэтому правильное решение это использование изменяемых обьектов (например StringBuilder).

    String result="";
    for(String s: arr){
    	result = result + s;
    }

    Еще один пример использования изменяемых an objectов — передача такого an object в метод. Это позволит вернуть результат в нем же, без создания лишних an objectов. При работе с an objectми большого размера, к примеру коллекциями, передача коллекции в метод для сортировки и возвращение результата в другой коллекции приводит к совершенно излишнему расходу ресурсов. (Ответ пользователя dasblinkenlight на Stack Overflow).

    Почему an object класса String неизменяем?

  9. Конструкторы классов Super и Sub

    10 lỗi các lập trình viên Java thường mắc phải - 2

    Lỗi biên dịch này là do lớp tổ tiên không có hàm tạo mặc định được xác định. Trong Java , trừ khi bạn tự chỉ định một hàm tạo của lớp, trình biên dịch sẽ tạo một hàm tạo mặc định không yêu cầu đối số. Nếu hàm tạo được mô tả trong lớp SuperSuper(String s){}, thì bản thân trình biên dịch sẽ không thêm bất cứ thứ gì. Đây là những gì chúng ta thấy trong ví dụ của chúng tôi.

    Hàm tạo của lớp Sub, bất kể cái nào, sẽ gọi hàm tạo mặc định của lớp Super, vì không có gì khác được chỉ định. Vì không có hàm tạo mặc định trong lớp Supernên điều này sẽ dẫn đến lỗi biên dịch.

    Giải pháp đầu tiên cho vấn đề này là thêm một hàm tạo mặc định vào lớpSuper

    public Super(){
        System.out.println("Super");
    }

    Tùy chọn thứ hai là loại bỏ hàm tạo mà chúng ta đã mô tả khỏi lớp Superđể trình biên dịch tạo một hàm tạo mặc định.

    Và tùy chọn cuối cùng là thêm lệnh gọi super(value)đến các hàm tạo của lớp Subđể hàm tạo của lớp hiện có được gọi thay vì hàm tạo mặc địnhSuper

    Hàm tạo của Super và Sub

  10. " " hoặc hàm tạo?

    Có hai cách để tạo chuỗi:

    //1. использовать двойные кавычки
    String x = "abc";

    //2. использовать конструктор
    String y = new String("abc");

    sự khác biệt giữa chúng là gì?

    Bạn có thể hiểu điều này qua các ví dụ sau:

    String a = "abcd";
    String b = "abcd";
    System.out.println(a == b);  // True
    System.out.println(a.equals(b)); // True
    
    String c = new String("abcd");
    String d = new String("abcd");
    System.out.println(c == d);  // False
    System.out.println(c.equals(d)); // True

    Để tìm hiểu thêm về cách các chuỗi được lưu trữ trong bộ nhớ, hãy đọc Tạo chuỗi Java bằng cách sử dụng "" hoặc Trình xây dựng? .

Các kế hoạch trong tương lai. Danh sách này dựa trên phân tích của tôi về một số lượng lớn các dự án Nguồn mở từ GitHub, các câu hỏi từ Stack Overflow và các truy vấn phổ biến trên Google. Tôi không muốn chứng minh rằng chúng thực sự nằm trong số mười sai lầm nghiêm trọng nhất, nhưng chúng thực sự rất phổ biến.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION