Trong lập trình Java, HashMap là một trong những thành phần quan trọng để lưu trữ và truy xuất dữ liệu. Bằng cách sử dụng cặp key-value, HashMap cho phép truy xuất các giá trị nhanh chóng và dễ dàng. Trong bài viết này, hãy cùng Rikkei Academy tìm hiểu chi tiết về Hashmap trong Java nhé!
HashMap trong Java là gì?
HashMap là một lớp trong Java Collection Framework. HashMap hoạt động dựa trên cơ chế bảng băm (hashing) để lưu trữ và truy xuất các phần tử dưới hình thức các cặp khóa-giá trị (key-value) không theo thứ tự nhất định. Trong HashMap, các khóa phải là duy nhất vì khóa được sử dụng để lấy giá trị tương ứng từ map.
Ví dụ: Một danh sách chứa thông tin cá nhân của sinh viên. Ở đây, tên sinh viên sẽ là khóa và các thông tin khác như địa chỉ, số điện thoại là giá trị tương ứng với khóa đó. Khi truy xuất thông tin của một sinh viên cụ thể, ta dùng khóa tương ứng với tên sinh viên và xuất ra các giá trị tương ứng.
Đặc điểm của HashMap trong Java?
- Sử dụng hàm băm (hash function): HashMap sử dụng một hàm băm (hash function) để gán khóa (key) với một chỉ số trong một mảng (array). Điều này cho phép tìm kiếm các giá trị nhanh chóng dựa trên key.
- Cặp key-value: Mỗi phần tử trong HashMap được lưu trữ dưới dạng một cặp key-value. Các khóa (key) được sử dụng để truy xuất giá trị tương ứng.
- Cho phép giá trị trùng lặp: HashMap cho phép giá trị trùng lặp, nhưng không cho phép key trùng lặp. Trường hợp xuất hiện key trùng lặp, giá trị trước đó có key sẽ bị ghi đè.
- Cho phép null: HashMap cho phép sử dụng key và value null. Điều này có nghĩa là có thể lưu trữ một giá trị null bằng key null và ngược lại.
- Không thứ tự: Các phần tử trong HashMap không được sắp xếp theo bất kỳ thứ tự nào mà có thể thay đổi khi thêm hoặc xóa. Nếu bạn muốn giữ thứ tự chèn, có thể sử dụng LinkedHashMap.
- Không đồng bộ: HashMap không đồng bộ, tức là nó không an toàn cho môi trường đa luồng. Nếu bạn cần sử dụng HashMap trong môi trường đa luồng, có thể sử dụng ConcurrentHashMap.
- Tự động điều chỉnh kích thước: Khi số lượng phần tử trong HashMap vượt quá ngưỡng tải trọng (load factor) của nó, HashMap sẽ tự động điều chỉnh kích thước
HashMap hoạt động như thế nào trong Java?
Một số khái niệm cần biết
HashMap hoạt động trên thuật toán băm (hashing) và sử dụng phương thức hashCode() và equals() trên khóa (key) cho các thao tác get và put. Trong đó:
- Phương thức hashcode(): được sử dụng để tính toán giá trị băm (hash value) của một khóa (key).
- Phương thức equals(): được sử dụng để so sánh hai khóa (key) với nhau để xác định chúng có bằng nhau hay không.
- Giá trị băm (hash value): được sử dụng để xác định vị trí lưu trữ các phần tử trong các bộ sưu tập này.
- Bucket: nếu hai khóa có cùng giá trị băm, chúng sẽ được lưu trữ trong cùng một vị trí, được gọi là bucket. Trong mỗi bucket, các cặp khóa-giá trị được lưu trữ dưới dạng các phần tử trong một danh sách liên kết đơn.
Cách hoạt động của Hashmap trong Java
Khi muốn truy xuất một giá trị (get) từ HashMap bằng khóa (key) tương ứng, HashMap sử dụng phương thức hashCode() để tính toán giá trị băm của khóa và xác định vị trí của bucket cần tìm. Sau đó, phương thức equals() được sử dụng để so sánh khóa cần tìm với các khóa bucket. Nếu có phần tử với khóa tương ứng được tìm thấy trong danh sách liên kết đơn của bucket, giá trị tương ứng với khóa đó sẽ được trả về. Nếu không có, HashMap sẽ trả về giá trị null.
Khi bạn thêm một cặp khóa-giá trị mới (put) vào HashMap, nó sử dụng phương thức equals() để kiểm tra tính duy nhất của khóa trong một bucket. Nếu equals() trả kết quả false (không trùng lặp), cặp khóa-giá trị mới sẽ được thêm vào danh sách liên kết đơn trong bucket tương ứng. Nếu equals trả kết quả true, giá trị mới sẽ ghi đè lên giá trị cũ.
Để đảm bảo rằng các phần tử được lưu trữ và truy xuất một cách hiệu quả, bạn nên cài đặt phương thức hashCode và equals cho lớp khóa của bạn. Điều này giúp đảm bảo rằng các khóa có cùng giá trị băm sẽ được so sánh để kiểm tra tính duy nhất của chúng trong HashMap.
Cấu trúc phân tầng của lớp HashMap trong Java
Lớp HashMap trong Java được xây dựng trên cơ sở AbstractMap, một lớp trừu tượng cung cấp một số phương thức cơ bản cho các lớp Map. HashMap là một lớp con của AbstractMap và triển khai giao diện Map.
Constructor của lớp HashMap trong Java
Constructor | Mô tả |
HashMap() | Tạo một HashMap trống với kích thước mặc định là 16 và tỷ lệ tải mặc định là 0.75. |
HashMap(int initialCapacity) | Tạo một HashMap trống với kích thước ban đầu được chỉ định và tỷ lệ tải mặc định là 0.75. |
HashMap(int initialCapacity, float loadFactor) | Tạo một HashMap trống với kích thước ban đầu và tỷ lệ tải được chỉ định. |
HashMap(Map<? extends K,? extends V> m) | Tạo một HashMap mới chứa các ánh xạ từ các khóa và giá trị được chỉ định. |
Trong đó:
- initialCapacity: kích thước ban đầu của HashMap (số lượng phần tử mà nó có thể chứa trước khi phải tăng kích thước).
- loadFactor: tỷ lệ tải của HashMap (khi số lượng phần tử trong HashMap vượt qua kích thước * tỷ lệ tải, HashMap sẽ tăng kích thước).
- m: một bản sao của HashMap khác.
Phương thức của lớp HashMap trong Java
Từ Java 5, cú pháp của HashMap là HashMap<K,V>, trong đó K đại diện cho Key hay là Khóa, và V đại diện cho Value hay là Giá trị.
Phương thức | Mô tả |
void clear() | Xóa tất cả các ánh xạ khỏi HashMap. |
boolean containsKey(Object key) | Kiểm tra xem HashMap có chứa khóa được chỉ định không. |
boolean containsValue(Object value) | Kiểm tra xem HashMap có chứa giá trị được chỉ định không. |
Set<Map.Entry<K, V>> entrySet() | Trả về một Set chứa tất cả các cặp khóa-giá trị trong HashMap. |
V get(Object key) | Trả về giá trị được liên kết với khóa được chỉ định. |
boolean isEmpty() | Kiểm tra xem HashMap có trống không. |
Set<K> keySet() | Trả về một Set chứa tất cả các khóa trong HashMap. |
V put(K key, V value) | Đặt một cặp khóa-giá trị mới vào HashMap. |
void putAll(Map<? extends K, ? extends V> m) | Đặt tất cả các cặp khóa-giá trị từ Map khác vào HashMap. |
V remove(Object key) | Xóa cặp khóa-giá trị được chỉ định khỏi HashMap. |
int size() | Trả về số lượng cặp khóa-giá trị có trong HashMap. |
Collection<V> values() | Trả về một Collection chứa tất cả các giá trị trong HashMap. |
Từ phiên bản Java 8, HashMap trong Java được bổ thêm nhiều phương thức mới phục vụ các thao các khác nhau:
Phương thức | Mô tả |
V getOrDefault(Object key, V defaultValue) | Trả về giá trị được liên kết với khóa được chỉ định. Nếu khóa không tồn tại, trả về giá trị mặc định. |
void forEach(BiConsumer<? super K, ? super V> action) | Thực hiện một hành động trên mỗi cặp khóa-giá trị trong HashMap. |
V putIfAbsent(K key, V value) | Đặt một cặp khóa-giá trị mới vào HashMap nếu khóa chưa tồn tại. |
boolean remove(Object key, Object value) | Xóa một cặp khóa-giá trị khỏi HashMap nếu khóa và giá trị được chỉ định khớp với một cặp có sẵn. |
boolean replace(K key, V oldValue, V newValue) | Thay thế giá trị cũ bằng giá trị mới nếu khóa và giá trị cũ đã được chỉ định khớp với một cặp có sẵn. |
V replace(K key, V value) | Thay thế giá trị hiện tại của khóa được chỉ định bằng giá trị mới. Trả về giá trị cũ hoặc null nếu không có giá trị nào được liên kết với khóa đó. |
Các tạo HashMap trong Java
Để tạo HashMap trong Java, trước hết bạn cần tải gói java.util.HashMap với cú pháp:
import java.util.HashMap;
Sau khi đã import gói, chúng ta tiến hành tạo Hashmap. Để tạo hashmap, bạn có thể sử dụng cú pháp sau:
HashMap<KeyType, ValueType> hashMapName = new HashMap<KeyType, ValueType>(); |
Trong đó:
- KeyType là kiểu dữ liệu của các khóa trong HashMap.
- ValueType là kiểu dữ liệu của các giá trị trong HashMap.
- hashMapName là tên của đối tượng HashMap.
Với cú pháp này, chúng ta đã chỉ định kiểu dữ liệu cho khóa và giá trị trong cùng một lần. Điều này cho phép ta kiểm tra dữ liệu của khóa và giá trị trong Hashmap và báo lỗi nếu có bất kỳ sai sót nào trong quá trình biên dịch. Đây cũng là cú pháp được ưu tiên khi lập trình các ứng dụng lớn và phức tạp.
Ngoài ra, ta có thể tạo hashmap bằng cú pháp:
HashMap map = new HashMap(); |
Cú pháp này không chỉ định kiểu dữ liệu cụ thể nào cho khóa và giá trị trong Hashmap, thay vào đó, chúng sẽ được xác định tự động giữa trên kiểu dữ liệu của các giá trị được thêm vào Hashmap về sau. Điều này cũng gây một số rủi ro khi sử dụng Hashmap.
Các thao tác phổ biến với HashMap trong Java
Trong Hashmap, các thao tác đều dựa trên cặp Key-Value (khóa – giá trị). Mỗi phần tử trong Hashmap sẽ được lưu trữ dưới dạng một entry (mục), bao gồm 1 key duy nhất và 1 giá trị tương ứng. Khi thao tác, ta dùng key (khóa) để truy xuất và lấy giá trị tương ứng. Một số thao tác phổ biến
Thêm một phần tử mới vào HashMap
Để thêm một phần tử mới vào HashMap, chúng ta có thể sử dụng phương thức put(key, value) của lớp HashMap. Trường hợp, khóa đã tồn tại, giá trị sẽ được cập nhật.
import java.util.HashMap;
public class AddElementToHashMapExample { public static void main(String[] args) { // Tạo ra một HashMap mới có kiểu dữ liệu là <String, Integer> HashMap<String, Integer> map = new HashMap<>(); // Thêm một phần tử vào HashMap map.put(“apple”, 1); // In ra HashMap để kiểm tra System.out.println(map); // Output: {apple=1} // Thêm một phần tử mới có cùng khóa nhưng giá trị khác map.put(“apple”, 2); // In ra HashMap để kiểm tra System.out.println(map); // Output: {apple=2} } } |
Truy xuất phần tử của HashMap
Để truy cập một phần tử trong HashMap, ta có thể sử dụng phương thức get() của lớp HashMap. Phương thức sẽ trả về giá trị tương ứng với khóa đã cho hoặc null nếu không tìm thấy khóa đó.
import java.util.HashMap;
public class GetElementFromHashMapExample { public static void main(String[] args) { // Tạo ra một HashMap mới có kiểu dữ liệu là <String, Integer> HashMap<String, Integer> map = new HashMap<>(); // Thêm một phần tử vào HashMap map.put(“apple”, 1); // Lấy giá trị của phần tử có khóa là “apple” Integer value = map.get(“apple”); // In giá trị lấy được ra màn hình System.out.println(value); // Output: 1 // Lấy giá trị của phần tử không tồn tại trong HashMap Integer nonExistingValue = map.get(“banana”); // In giá trị lấy được ra màn hình System.out.println(nonExistingValue); // Output: null } } |
Duyệt các phần tử của HashMap trong Java
Để duyệt các phần tử của Hashmap trong Java, ta có thể sử dụng các cách sau:
- Sử dụng vòng lặp for
import java.util.HashMap;
public class TraverseHashMapUsingForLoop { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put(“A”, 1); map.put(“B”, 2); map.put(“C”, 3); // Duyệt các phần tử của HashMap bằng vòng lặp for for (String key : map.keySet()) { Integer value = map.get(key); System.out.println(key + “: ” + value); } } } |
- Sử dụng Map.Entry interface
import java.util.HashMap;
import java.util.Map; public class TraverseHashMapUsingMapEntry { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put(“A”, 1); map.put(“B”, 2); map.put(“C”, 3); // Duyệt các phần tử của HashMap bằng cách sử dụng Map.Entry interface for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + “: ” + value); } } } |
- Sử dụng Iterator
import java.util.HashMap;
import java.util.Iterator; import java.util.Map; public class TraverseHashMapUsingIterator { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put(“A”, 1); map.put(“B”, 2); map.put(“C”, 3); // Duyệt các phần tử của HashMap bằng Iterator Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + “: ” + value); } } } |
Cập nhật giá trị của phần tử HashMap
Để cập nhật giá trị của một phần tử trong HashMap, chúng ta cũng có thể sử dụng phương thức put() của lớp HashMap. Khi thực hiện phương thức này với một khóa đã tồn tại trong HashMap, giá trị cũ sẽ bị thay thế bằng giá trị mới.
import java.util.HashMap;
public class UpdateElementInHashMap { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put(“A”, 1); map.put(“B”, 2); map.put(“C”, 3); // Cập nhật giá trị của phần tử trong HashMap map.put(“B”, 4); // In HashMap để kiểm tra xem phần tử đã được cập nhật thành công hay chưa System.out.println(map); // In ra: {A=1, B=4, C=3} } } |
Xóa phần tử HashMap
Để xóa một phần tử khỏi HashMap, chúng ta có thể sử dụng phương thức remove() của lớp HashMap.
import java.util.HashMap;
public class RemoveElementFromHashMap { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put(“A”, 1); map.put(“B”, 2); map.put(“C”, 3); // Xóa một phần tử khỏi HashMap map.remove(“B”); // In HashMap để kiểm tra xem phần tử đã được xóa thành công hay chưa System.out.println(map); // In ra: {A=1, C=3} } } |
Kiểm tra sự tồn tại của khóa
Để kiểm tra sự tồn tại của một khóa trong HashMap, ta sử dụng phương thức containsKey(key). Phương thức sẽ trả về true nếu HashMap chứa khóa đã cho và false nếu không.
import java.util.HashMap;
public class CheckKeyInHashMapExample { public static void main(String[] args) { // Tạo ra một HashMap mới có kiểu dữ liệu là <String, Integer> HashMap<String, Integer> map = new HashMap<>(); // Thêm một số phần tử vào HashMap map.put(“apple”, 1); map.put(“banana”, 2); map.put(“cherry”, 3); // Kiểm tra sự tồn tại của khóa “apple” trong HashMap boolean containsKey = map.containsKey(“apple”); // In kết quả ra màn hình System.out.println(containsKey); // Output: true // Kiểm tra sự tồn tại của khóa “durian” trong HashMap boolean nonExistingKey = map.containsKey(“durian”); // In kết quả ra màn hình System.out.println(nonExistingKey); // Output: false } } |
Lấy tất cả các khóa trong HashMap
Để lấy tất cả các khóa trong HashMap, ta sử dụng phương thức keySet(). Phương thức sẽ trả về một Set chứa tất cả các khóa trong HashMap.
Lưu ý: Khi sử dụng phương thức keySet(), bạn cần sử dụng interface Set để đại diện cho tập hợp các khóa duy nhất và không có thứ tự của HashMap bằng cách tải gói java.util.Set.
import java.util.HashMap;
import java.util.Set;//tải gói Set public class GetAllKeysFromHashMapExample { public static void main(String[] args) { // Tạo ra một HashMap mới có kiểu dữ liệu là <String, Integer> HashMap<String, Integer> map = new HashMap<>(); // Thêm một số phần tử vào HashMap map.put(“apple”, 1); map.put(“banana”, 2); map.put(“cherry”, 3); // Lấy tất cả các khóa trong HashMap Set<String> keys = map.keySet(); // In tất cả các khóa ra màn hình System.out.println(keys); // Output: [apple, banana, cherry] } } |
Lấy tất cả các giá trị trong HashMap
Để lấy tất cả các giá trị trong HashMap, ta sử dụng phương thức values().
Lưu ý: Khi sử dụng phương thức values(), bạn cần sử dụng interface Collection để đại diện cho tập hợp các giá trị của HashMap bằng cách tải gói java.util.Collection.
import java.util.HashMap;
import java.util.Collection;//tải gói Collection public class GetAllValuesFromHashMapExample { public static void main(String[] args) { // Tạo ra một HashMap mới có kiểu dữ liệu là <String, Integer> HashMap<String, Integer> map = new HashMap<>(); // Thêm một số phần tử vào HashMap map.put(“apple”, 1); map.put(“banana”, 2); map.put(“cherry”, 3); // Lấy tất cả các giá trị trong HashMap Collection<Integer> values = map.values(); // In tất cả các giá trị ra màn hình System.out.println(values); // Output: [1, 2, 3] } } |
Lấy tất cả các cặp khóa – giá trị trong HashMap
Để lấy tất cả các cặp khóa – giá trị trong HashMap, ta sử dụng phương thức entrySet(). Phương thức sẽ trả về một Set chứa tất cả các cặp khóa – giá trị trong HashMap dưới dạng Map.Entry.
import java.util.HashMap;
import java.util.Set; public class GetAllEntriesFromHashMapExample { public static void main(String[] args) { // Tạo ra một HashMap mới có kiểu dữ liệu là <String, Integer> HashMap<String, Integer> map = new HashMap<>(); // Thêm một số phần tử vào HashMap map.put(“apple”, 1); map.put(“banana”, 2); map.put(“cherry”, 3); // Lấy tất cả các cặp khóa – giá trị trong HashMap Set<Map.Entry<String, Integer>> entries = map.entrySet(); // In tất cả các cặp khóa – giá trị ra màn hình for (Map.Entry<String, Integer> entry : entries) { System.out.println(entry.getKey() + ” – ” + entry.getValue()); } // Output: // apple – 1 // banana – 2 // cherry – 3 } } |
Phân biệt Map, HashSet và HashMap trong Java
Trong Java, Map, HashSet và HashMap đều là các lớp được sử dụng để lưu trữ và truy cập các phần tử. Tuy nhiên, chúng có sự khác nhau về cách thức lưu trữ và truy cập dữ liệu:
Map
Map là một cấu trúc dữ liệu dùng để lưu trữ các cặp key-value. Với Map, các key phải là duy nhất và các value có thể trùng nhau. Map không đảm bảo thứ tự của các phần tử được lưu trữ, và có thể lặp lại các giá trị value.
HashSet
HashSet là một cấu trúc dữ liệu dùng để lưu trữ các phần tử không trùng nhau. Với HashSet, các phần tử không được đánh chỉ số và không có thứ tự cụ thể. HashSet cũng không cho phép lưu trữ các phần tử null.
Nếu cần kiểm tra tính duy nhất của các phần tử, thì HashSet được ưu tiên sử dụng.
HashMap
HashMap là một cấu trúc dữ liệu dùng để lưu trữ các cặp key-value, tương tự như Map. Tuy nhiên, HashMap sử dụng bảng băm (hashing) để lưu trữ và truy cập dữ liệu, giúp tìm kiếm và truy cập các phần tử nhanh chóng hơn. HashMap cũng không đảm bảo thứ tự của các phần tử được lưu trữ, và có thể lặp lại các giá trị value.
Nếu cần lưu trữ và truy xuất thông tin đối tượng với số lượng lớn, thì HashMap được ưu tiên sử dụng để tối ưu thời gian truy cập dữ liệu.
Kết luận
Như vậy, Rikkei Academy đã cung cấp cho bạn các thông tin chi tiết về Hashmap trong Java trên nhiều phương diện bao gồm khái niệm, cách hoạt động đến các thao tác phổ biến đi kèm ví dụ. Hy vọng qua bài viết này đã giúp bạn hiểu hơn về HashMap trong Java cũng như cách sử dụng lớp này trong Java
Nếu bạn đang tìm địa chỉ uy tín cung cấp khóa học lập trình Java, tham khảo ngay Rikkei Academy! Chương trình được thiết kế tinh gọn với các kiến thức, kỹ năng bám sát thực tế cùng giảng viên luôn hỗ trợ 24/7 sẽ giúp bạn nhanh chóng trở thành lập trình viên trong 6 tháng! Đăng ký để nhận tư vấn miễn phí ngay tại đây!