1. Interface Collection là gì
Trong Java, interface giống như một hợp đồng: nếu một lớp triển khai (implements) một interface, nó bắt buộc phải cung cấp triển khai cho tất cả các phương thức của interface đó. Bản thân interface không lưu trữ trạng thái và không chứa mã (gần như vậy: từ Java 8 có các phương thức default, nhưng hiện giờ ý tưởng nền tảng mới là quan trọng).
Collection — interface cơ sở cho phần lớn collections trong Java. Nó xác định một collection biết làm gì: thêm phần tử, xóa, lấy kích thước, kiểm tra sự hiện diện của phần tử, v.v.
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
boolean add(E e);
boolean remove(Object o);
void clear();
Iterator<E> iterator();
// ... và còn rất nhiều phương thức hữu ích
}
Các phương thức then chốt:
- add(E e) — thêm phần tử.
- remove(Object o) — xóa phần tử.
- size() — lấy số lượng phần tử.
- isEmpty() — kiểm tra collection có rỗng hay không.
- contains(Object o) — kiểm tra sự hiện diện của phần tử.
- clear() — làm trống collection.
- iterator() — lấy iterator để duyệt.
Vì sao Map không kế thừa Collection?
Map đứng riêng trong các collections. Bởi vì Map là tập hợp các cặp “khóa → giá trị”, chứ không chỉ là một tập phần tử. Nó có hợp đồng khác và bộ phương thức khác. Ví dụ, trong Map không có phương thức add, vì việc thêm được thực hiện thông qua put(key, value), và không có ý nghĩa khi kiểm tra sự hiện diện của giá trị nếu không biết khóa.
2. Hệ phân cấp các collection
“Cây” các interface chính có thể hình dung như sau:
Iterable
|
Collection
/ | \
List Set Queue
|
Deque
- Iterable — interface cơ bản nhất: mọi thứ có thể lặp bằng vòng for-each.
- Collection — mở rộng Iterable, bổ sung các thao tác làm việc với tập phần tử.
- Ba nhánh chính:
- List — danh sách có thứ tự, cho phép trùng lặp.
- Set — tập hợp phần tử duy nhất, thứ tự phụ thuộc vào triển khai.
- Queue — hàng đợi (thường là FIFO); biến thể — Deque (hàng đợi hai đầu).
Còn Map sống tách biệt:
Map
/ \
HashMap TreeMap
Trực quan hóa hệ phân cấp (sơ đồ)
+--------------------+
| Iterable<E> |
+--------------------+
|
+--------------------+
| Collection<E> |
+--------------------+
/ | \
+--------+ +-------+ +-------+
| List | | Set | | Queue |
+--------+ +-------+ +-------+
|
+------+
|Deque |
+------+
+--------------------+
| Map<K,V> |
+--------------------+
3. List: collection có thứ tự và cho phép trùng lặp
List là collection mà:
- Thứ tự phần tử quan trọng (thứ nhất, thứ hai, thứ ba…).
- Cho phép các phần tử giống nhau (trùng lặp).
- Có thể lấy phần tử theo chỉ số (list.get(2)), thay thế, chèn vào bất kỳ vị trí nào.
Ví dụ triển khai: ArrayList — truy cập theo chỉ số nhanh; LinkedList — tốt khi chèn/xóa nhiều ở giữa.
import java.util.*;
List<String> shoppingList = new ArrayList<>();
shoppingList.add("Sữa");
shoppingList.add("Bánh mì");
shoppingList.add("Phô mai");
shoppingList.add("Bánh mì"); // Cho phép trùng lặp!
System.out.println(shoppingList.get(1)); // "Bánh mì"
Các phương thức thường dùng của List:
- add(E e), add(int index, E e)
- get(int index), set(int index, E e)
- remove(int index), remove(Object o)
- indexOf(Object o), lastIndexOf(Object o)
4. Set: tập hợp phần tử duy nhất
Set là collection mà:
- Mỗi phần tử là duy nhất (không có trùng lặp).
- Thứ tự lưu trữ không được đảm bảo ở HashSet, có thể được sắp xếp ở TreeSet hoặc theo thứ tự chèn ở LinkedHashSet.
Ví dụ triển khai: HashSet, TreeSet, LinkedHashSet.
import java.util.*;
Set<String> uniqueNames = new HashSet<>();
uniqueNames.add("Anya");
uniqueNames.add("Boris");
uniqueNames.add("Anya"); // Không thêm — đã tồn tại!
System.out.println(uniqueNames.contains("Anya")); // true
System.out.println(uniqueNames.size()); // 2
Các phương thức thường dùng của Set:
- add(E e), remove(Object o)
- contains(Object o)
- size(), isEmpty()
5. Map: collection các cặp khóa–giá trị
Map là collection trong đó:
- Mỗi phần tử là cặp khóa → giá trị.
- Khóa là duy nhất, giá trị có thể lặp lại.
- Truy cập nhanh theo khóa.
Ví dụ triển khai: HashMap, TreeMap, LinkedHashMap.
import java.util.*;
Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Anya", "+19991112233");
phoneBook.put("Boris", "+19994445566");
phoneBook.put("Anya", "+19990001122"); // Sẽ ghi đè số của Anya!
System.out.println(phoneBook.get("Anya")); // "+19990001122"
System.out.println(phoneBook.containsKey("Boris")); // true
Các phương thức thường dùng của Map:
- put(K key, V value), get(K key)
- remove(K key)
- containsKey(K key), containsValue(V value)
- keySet(), values(), entrySet()
6. Trực quan hóa hệ phân cấp: tất cả trên một hình
Bảng tóm tắt nhỏ:
| Giao diện | Mô tả | Ví dụ triển khai | Đặc điểm chính |
|---|---|---|---|
|
Danh sách có thứ tự | |
Truy cập theo chỉ số, cho phép trùng lặp |
|
Tập các giá trị duy nhất | |
Chỉ các phần tử duy nhất |
|
Các cặp khóa–giá trị | |
Khóa là duy nhất, giá trị tùy ý |
Sơ đồ hệ phân cấp:
Collection
/ | \
List Set Queue
|
Deque
Map (riêng biệt)
7. Khi nào dùng interface nào
List
- Khi thứ tự phần tử quan trọng (ví dụ, lịch sử thao tác của người dùng).
- Khi cần trùng lặp (ví dụ, các dòng hàng trong đơn đặt hàng).
- Khi cần truy cập/thay thế nhanh theo chỉ số.
Set
- Khi cần tính duy nhất (email, tên đăng nhập, id).
- Khi không cần thứ tự, hoặc ngược lại — cần một tập được sắp xếp tự động (TreeSet).
Map
- Khi cần ánh xạ khóa và giá trị (id → đối tượng, đăng nhập → hồ sơ).
- Khi cần tìm kiếm nhanh theo khóa.
- Khi khóa phải là duy nhất, còn giá trị thì không.
8. Những lỗi thường gặp khi làm việc với hệ phân cấp collections
Lỗi 1: Sử dụng interface không phù hợp trong khai báo biến. Nếu bạn viết ArrayList<String> list = new ArrayList<>();, bạn đang gắn chặt vào một triển khai cụ thể. Nên ưu tiên List<String> list = new ArrayList<>(); — như vậy dễ thay thế triển khai hơn.
Lỗi 2: Cố gắng thêm bản sao vào Set và kỳ vọng chúng sẽ xuất hiện. Đây không phải bug, mà là đặc điểm: Set theo định nghĩa không lưu trữ trùng lặp. Việc chèn lặp lại sẽ bị bỏ qua.
Lỗi 3: Sử dụng Map như một collection thông thường. Map không phải là list hay set. Để duyệt, hãy dùng keySet(), values() hoặc entrySet().
Lỗi 4: Kỳ vọng có thứ tự trong HashSet hoặc HashMap. HashSet và HashMap không đảm bảo thứ tự. Nếu thứ tự quan trọng — hãy dùng LinkedHashSet hoặc LinkedHashMap.
Lỗi 5: Dùng List cho các phần tử phải duy nhất. Nếu cần tính duy nhất — hãy dùng Set. List không ngăn trùng lặp.
GO TO FULL VERSION