-
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ớpArrayList
là một lớp tĩnh riêng tư bên trong(private static class)
của lớpArrays
và đây không phải là một lớp.java.util.ArrayList.
Lớp nàyjava.util.Arrays.ArrayList
chứa các phương thứcset()
,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.ArrayList
có thể lấy làm tham số cho tất cả các đối tượng thực hiện một giao diệnCollection
, 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).
-
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ó
List
thànhSet
. Việc chuyển đổi sangSet
sẽ 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.
-
Loại bỏ một phần tử khỏi
List
vòng lặpHã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
List
sẽ 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-each
hoạ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
Trong kiểu vòng lặpnext()
phải được gọi trướcremove()
.for-each
, trình biên dịch sẽ gọi phương thức nàyremove()
và chỉ sau đónext()
nó mới gây ra lỗiConcurrentModificationException
. Bạn có thể nhìn vào mãArrayList.iterator()
. -
Hashtable
chống lạiHashMap
.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ữaHashtable
andHashMap
là nó đượcHashtable
đồng bộ hóa nên không nên sử dụngHashtable
ở đâuHashMap
.HashMap so với Bản đồ cây so với Bảng băm so với LinkedHashMap .
-
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>
— почитайте вот эту и эту ссылки. -
Уровень доступа
Очень часто для полей класса разработчики используют модификатор доступа
public
. Так проще получить meaning поля напрямую. Правильнее использовать How можно более ограниченный доступ к членам класса. ArrayList
противLinkedList
Когда разработчики не знают чем отличается
ArrayList
отLinkedList
, они используют первый в силу его большей известности. Однако, есть огромная разница в производительности между ними. На самом деле, выбор между ними должен быть продиктован их внутренними особенностями —ArrayList
позволяет быстро производить доступ к произвольному элементу массива, аLinkedList
— быстро добавлять/удалять элементы в массиве. Почитайте статью по ссылке ArrayList vs. LinkedList чтобы понять причины их разной производительности.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).
-
Конструкторы классов
Super
иSub
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
Super
làSuper(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ớpSuper
, vì không có gì khác được chỉ định. Vì không có hàm tạo mặc định trong lớpSuper
nê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ớp
Super
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ớpSub
để hàm tạo của lớp hiện có được gọi thay vì hàm tạo mặc địnhSuper
-
" " 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? .
GO TO FULL VERSION