Collection trong Java là một phần quan trọng của Java Collections Framework, cung cấp một tập hợp các phương thức và tính năng để làm việc với các tập hợp các đối tượng. Đừng bỏ lỡ bài viết này của Rikkei Academy nếu bạn đang tìm hiểu về vấn đề này nhé!
Collection trong Java là gì?
Trước khi đi vào tìm hiểu khái niệm này, trước hết chúng ta cần biết về Java Collections Framework.
Java Collections Framework là gì?
Java Collections Framework là một tập hợp các class (lớp) và interface (giao diện) được sử dụng để lưu trữ và quản lý các đối tượng dữ liệu trong chương trình Java. Nói đơn giản, nó cung cấp các class (lớp) và interface (giao diện) để đại diện cho các cấu trúc dữ liệu như List, Set, Queue và Map để thực hiện các thuật toán phổ biến như sắp xếp, tìm kiếm và ghép nối dữ liệu. Mục đích của collection framework:
- Lưu trữ và quản lý các đối tượng
- Tối ưu hóa hiệu suất
- Tiết kiệm thời gian và công sức.
- Tăng tính tái sử dụng của mã
Cấu trúc phân cấp của Java Collections Framwork?
- Interface (giao diện)
- Class (Lớp)
- Algorithms (thuật toán)
Collection và collection trong Java
Trong Java Collections Framework:
- Collection (không có “s” ở cuối) là một interface, đại diện cho một tập hợp các phần tử. Nó là interface cha của tất cả các interface khác như List, Set, Queue và Deque. Bên cạnh đó, tất cả các lớp triển khai của các interface này đều phải triển khai các phương thức được định nghĩa trong Collection interface.
- Collections (có “s” ở cuối) là một lớp tiện ích (utility class) trong Java cung cấp một số phương thức tĩnh (static methods) để thao tác trên các collection và có thể được sử dụng để sắp xếp, tìm kiếm, lấy phần tử lớn nhất, chuyển đổi các collection….
Collection trong Java
Collection hay Collection Interface trong Java là một interface gốc của hệ thống các interface như List, Set và Queue và lớp con. Collection không có lớp triển khai cụ thể. Tuy nhiên, các interface con của Collection sở hữu các lớp triển khai khác nhau. Những lớp này cung cấp các cách khác nhau để thao tác và xử lý dữ liệu trong Collection, phù hợp với các nhu cầu và yêu cầu khác nhau của ứng dụng.
Interface Collection xác định một số phương thức cơ bản mà tất cả các lớp triển khai (implement) của các interface đều phải triển khai.
Phương thức của Collection Interface
Một số các phương thức được định nghĩa trong interface Collection.
Phương thức | Mô tả |
boolean add(E e) | Thêm một phần tử vào Collection. Trả về true nếu phần tử được thêm thành công. |
boolean addAll(Collection<? extends E> c) | Thêm tất cả các phần tử từ một Collection khác vào Collection hiện tại. Trả về true nếu ít nhất một phần tử được thêm thành công. |
void clear() | Xóa tất cả các phần tử trong Collection. |
boolean contains(Object o) | Kiểm tra xem Collection có chứa phần tử đã cho hay không. Trả về true nếu phần tử có trong Collection. |
boolean containsAll(Collection<?> c) | Kiểm tra xem Collection có chứa tất cả các phần tử của một Collection khác hay không. Trả về true nếu tất cả các phần tử có trong Collection. |
boolean equals(Object o) | So sánh Collection với một đối tượng khác để xem chúng có bằng nhau hay không. |
int hashCode() | Trả về giá trị hash code của Collection. |
boolean isEmpty() | Kiểm tra xem Collection có rỗng hay không. Trả về true nếu Collection không có phần tử nào. |
Iterator<E> iterator() | Trả về một đối tượng Iterator để duyệt qua các phần tử của Collection. |
boolean remove(Object o) | Loại bỏ một phần tử khỏi Collection. Trả về true nếu phần tử được loại bỏ thành công. |
boolean removeAll(Collection<?> c) | Loại bỏ tất cả các phần tử của một Collection khác khỏi Collection hiện tại. Trả về true nếu ít nhất một phần tử được loại bỏ thành công. |
boolean retainAll(Collection<?> c) | Giữ lại tất cả các phần tử của một Collection khác trong Collection hiện tại và loại bỏ các phần tử không thuộc Collection đó. Trả về true nếu Collection thay đổi sau khi gọi phương thức này. |
int size() | Trả về số lượng phần tử trong Collection. |
Object[] toArray() | Chuyển đổi Collection thành một mảng các đối tượng. |
<T> T[] toArray(T[] a) | Chuyển đổi Collection thành một mảng các đối tượng, sử dụng mảng đã cho nếu đủ chỗ, hoặc tạo một mảng mới với cùng kiểu phần tử nếu cần thiết. |
List Interface
Đây là interface con cua Collection Interface, dành cho dữ liệu kiểu list. List trong Java đại diện cho một danh sách các phần tử có thứ tự và cho phép chứa các phần tử trùng lặp.
Class triển khai của List interface
ArrayList
ArrayList được xây dựng trên một mảng động. ArrayList có thể tự động thay đổi kích thước của mảng khi cần thiết. Ngoài ra, nó cho phép lưu trữ và truy cập ngẫu nhiên vào các phần tử bằng cách sử dụng chỉ số (index) và cho phép trùng lặp phần tử.
- Thích hợp cho việc truy cập ngẫu nhiên và thêm phần tử vào cuối danh sách.
LinkedList
LinkedList được xây dựng trên một danh sách liên kết. LinkedList cho phép lưu trữ và truy cập dữ liệu có thứ tự. Đồng thời, nó cũng cho phép trùng lặp phần tử có thể thêm và xóa phần tử ở đầu hoặc cuối danh sách một cách hiệu quả hơn so với ArrayList.
- Thích hợp cho việc thêm và xóa phần tử ở đầu và cuối danh sách hơn so với ArrayList
Vector
Tương tự như ArrayList, nhưng được đồng bộ hóa để đảm bảo tính toàn vẹn của dữ liệu trong trường hợp có nhiều luồng (thread) truy cập vào cùng một thời điểm. Tuy nhiên, Vector hiếm khi được sử dụng trong các ứng dụng hiện đại vì nó có hiệu suất kém hơn so với ArrayList.
Stack
Triển khai bằng cách sử dụng một ngăn xếp (stack) để lưu trữ các phần tử. Stack cung cấp các phương thức để đẩy (push) và rút (pop) các phần tử vào và ra khỏi ngăn xếp. Stack không được sử dụng rộng rãi trong các ứng dụng hiện đại, nhưng nó có thể hữu ích trong một số tình huống đặc biệt.
Set Interface
Set Interface đại diện cho một tập hợp các phần tử duy nhất (không trùng lặp). Tuy nhiên, nó, không đảm bảo thứ tự phần tử (trừ LinkedHashSet) có nghĩa là các phần tử được thêm vào Set có thể được sắp xếp theo bất kỳ thứ tự nào.Các lớp triển khai phổ biến của Set là HashSet, LinkedHashSet và TreeSet.
Class triển khai của Set interface
HashSet
Được xây dựng trên một bảng băm (hash table). HashSet sử dụng hàm băm (hash function) để tính toán vị trí của phần tử trong bảng băm và thêm phần tử vào vị trí đó. Đồng thời, HashSet sử dụng hàm băm để tìm vị trí của phần tử. Nếu vị trí đó chứa một phần tử khác, phần tử mới sẽ không được thêm vào. Mục đích sử dụng:
- Lưu trữ các phần tử duy nhất (không trùng lặp).
- Không đảm bảo thứ tự phần tử.
- Thích hợp cho việc kiểm tra tính duy nhất của phần tử và thao tác tập hợp.
LinkedHashSet
Kế thừa từ HashSet và được xây dựng trên một danh sách liên kết. LinkedHashSet lưu trữ các phần tử duy nhất và duy trì thứ tự chèn phần tử. Điều này có nghĩa là khi bạn thêm một phần tử vào LinkedHashSet, nó sẽ được thêm vào cuối danh sách và giữ nguyên vị trí đó.
- Thích hợp cho việc kiểm tra tính duy nhất của phần tử và thao tác tập hợp.
TreeSet
Được triển khai bằng cách sử dụng cây đỏ-đen (Red-Black Tree) để lưu trữ các phần tử. TreeSet được sử dụng để lưu trữ các phần tử duy nhất, không trùng lặp và duy trì thứ tự sắp xếp của các phần tử.
- Thích hợp cho việc kiểm tra tính duy nhất của phần tử và thao tác tập hợp có thứ tự.
EnumSet
Được sử dụng để lưu trữ các hằng số enum. EnumSet triển khai bằng cách sử dụng một mảng bit (bit array) để lưu trữ các phần tử, do đó nó rất hiệu quả trong việc lưu trữ các hằng số enum.
Queue Interface
Queue interface duy trì thứ tự FIFO (First In First Out) tương tự như hàng đợi thực tế. Interface này dành cho việc lưu trữ tất cả các phần tử mà thứ tự của các phần tử đó quan trọng, nghĩa là các phần tử được thêm vào đầu tiên sẽ được xử lý đầu tiên. Các lớp triển khai phổ biến của Queue là LinkedList, PriorityQueue và ArrayBlockingQueue.
Lớp triển khai Queue interface
PriorityQueue
Nó được triển khai bằng cách sử dụng cấu trúc dữ liệu hàng đợi ưu tiên để lưu trữ các phần tử. PriorityQueue được sử dụng để xử lý các phần tử theo độ ưu tiên, nghĩa là phần tử với độ ưu tiên cao được xử lý trước.
- Thích hợp cho các tác vụ xếp hàng và xử lý theo độ ưu tiên.
ArrayDeque
Nó được triển khai bằng cách sử dụng mảng động để lưu trữ các phần tử. ArrayDeque được sử dụng để hỗ trợ các hoạt động thêm và xóa phần tử ở cả hai đầu của danh sách.
- Thích hợp cho việc sử dụng như Stack (ngăn xếp) hoặc Queue (hàng đợi).
Deque Interface
Đây là một biến thể nhỏ của cấu trúc dữ liệu Queue. Deque, còn được gọi là double-ended queue, là một cấu trúc dữ liệu nơi chúng ta có thể thêm và loại bỏ các phần tử từ cả hai đầu của hàng đợi. Interface này kế thừa Queue interface. Lớp triển khai interface này là ArrayDeque.
Map Interface
Map InterfaceKhông kế thừa từ Collection Interface, nhưng là một thành phần quan trọng trong Collections Framework. Nó lưu trữ dữ liệu dưới dạng các cặp key-value, trong đó mỗi key là duy nhất và truy xuất dữ liệu dựa trên key đó. Các lớp triển khai phổ biến của Map là HashMap, LinkedHashMap và TreeMap.
Lớp triển khai của Map interface
HashMap
Một lớp triển khai Map interface, nó được triển khai bằng cách sử dụng bảng băm để lưu trữ các cặp key-value (khóa-giá trị). HashMap cho phép trùng lặp giá trị, nhưng không cho phép trùng lặp khóa, và không đảm bảo thứ tự phần tử.
- Thích hợp cho việc tra cứu và thao tác dữ liệu dựa trên khóa.
LinkedHashMap
Kế thừa HashMap và triển khai bằng cách sử dụng danh sách liên kết để lưu trữ các cặp key-value (khóa-giá trị). LinkedHashMap cho phép trùng lặp giá trị, nhưng không cho phép trùng lặp khóa, và duy trì thứ tự chèn phần tử.
- Thích hợp cho việc tra cứu và thao tác dữ liệu dựa trên khóa.
TreeMap
Một lớp triển khai Map interface, nó được triển khai bằng cách sử dụng cây đỏ-đen (Red-Black Tree) để lưu trữ các cặp key-value (khóa-giá trị). TreeMap cho phép trùng lặp giá trị, nhưng không cho phép trùng lặp khóa, và duy trì thứ tự sắp xếp phần tử.
- Thích hợp được sử dụng trong các tình huống cần truy xuất các phần tử theo thứ tự của khóa
Collections trong Java
Trong cấu trúc phân tầng của Java Collections Framework bao gồm: algorithm (thuật toán). Đây là nơi Collections trong Java hoạt động. Collections trong Java cung cấp một số thuật toán để thực hiện các tác vụ phổ biến trên các collection. Nói dễ hiểu, các thuật toán này được định nghĩa trong lớp tiện ích Collections của Java. Mặc dù phần lớn các thuật toán này được dùng chủ yếu trong List nhưng nó vẫn được ứng dụng trong các interface khác:
Thuật toán | Mô tả |
Collections.sort() | Sắp xếp một List theo thứ tự tăng dần. |
Collections.binarySearch() | Tìm kiếm một phần tử trong một List đã được sắp xếp. |
Collections.reverse() | Đảo ngược thứ tự các phần tử trong một List. |
Collections.shuffle() | Trộn ngẫu nhiên thứ tự các phần tử trong một List. |
Collections.fill() | Gán một giá trị cụ thể cho tất cả các phần tử trong một List. |
Collections.copy() | Sao chép các phần tử từ một List sang một List khác. |
Collections.addAll() | Thêm tất cả các phần tử từ một mảng hoặc một Collection vào một Collection khác. |
Collections.frequency() | Đếm số lần xuất hiện của một phần tử trong một Collection. |
Collections.disjoint() | Kiểm tra xem hai Collection có phần tử chung hay không. |
Collections.min()
Collections.max() |
Tìm phần tử nhỏ nhất hoặc lớn nhất trong một Collection. |
Một số vấn đề liên quan đến Collection trong Java
Mặc dù Java Collection Framework cung cấp nhiều lớp và interface hữu ích để lưu trữ, xử lý và quản lý dữ liệu, tuy nhiên cũng có một số khuyết điểm như hiệu suất không tối ưu với các Collection lớn, không đảm bảo về thứ tự các phần tử,…Để giải quyết các vấn đề trên, chúng ta có thể sử dụng thêm Iterator Interface, comparator và comparable Interface
Iterator
Với các Collection trong Java lớn, việc truy cập ngẫu nhiên đến các phần tử trong Collection có thể mất nhiều thời gian và tài nguyên do vị trí của phần tử trong Collection không được lưu trữ liên tục trong bộ nhớ. Hơn nữa, nếu sử dụng vòng lặp for-each để duyệt qua các phần tử, ta không thể thực hiện các hoạt động như xóa hoặc thêm phần tử trong quá trình duyệt.
Để giải quyết vấn đề truy cập ngẫu nhiên đến phần tử trong Collection, ta sử dụng Iterator. Iterator là một interface trong Java Collection Framework, cho phép truy cập tuần tự đến các phần tử trong Collection mà không cần biết vị trí của chúng trong Collection.
Comparable và Comparator Interface
Java Collection Framework không đảm bảo thứ tự của các phần tử trong Collection. Nếu không sử dụng Comparable hoặc Comparator để định nghĩa tiêu chí so sánh, thứ tự của các phần tử khi sắp xếp có thể không đúng với mong đợi.
- Interface Comparable được cài đặt bởi một lớp đối tượng, cho phép định nghĩa phương thức compareTo() để so sánh đối tượng với đối tượng khác. Nếu một đối tượng cài đặt interface Comparable, ta có thể sử dụng phương thức sort() của lớp Collections để sắp xếp các đối tượng theo thứ tự tăng dần hoặc giảm dần.
- Với interface Comparator, ta có thể tạo ra một phương thức so sánh riêng để sắp xếp các phần tử trong một Collection theo một tiêu chí nhất định.
Kết luận
Như vậy, Rikkei Academy đã giúp bạn hiểu về Collection, Collections trong Java nói riêng và Java Collection Framework nói chung. Hy vọng bài viết này đã giúp bạn hiểu rõ hơn về các khái niệm này, cách phân biệt cũng như vai trò của chúng trong Java Collection Framework.
Nếu bạn đang muốn tìm hiểu về khóa học lập trình, tham khảo ngay Rikkei Academy! Với lộ trình tinh gọn, bám sát thực tế cùng sự hỗ trợ sát sao 24/7 từ giảng viên sẽ giúp bạn chinh phục ngôn ngữ lập trình Java trong 6 tháng. Đặc biệt, bạn không cần phải lo lắng vấn đề công việc khi Rikkei Academy cam kết việc làm bằng văn bản! Đăng ký nhận tư vấn miễn phí ngay!